Exemple #1
0
 def get_article(self):
     article="Newsgroups: "+self.newsgroups+"\n"
     article=article+"From: "+formataddr([self.nick_encoded,self.email])+"\n"
     article=article+"Subject: "+self.subject_encoded+"\n"
     if self.references!="":
         article=article+"References: "+self.references+"\n"
     self.references=""
     article=article+"User-Agent: "+self.user_agent+"\n"
     article=article+"MIME-Version: 1.0\n"
     article=article+"Content-Type: text/plain; charset="+self.output_charset+"\n"
     if self.output_charset.lower()=="us-ascii":
         article=article+"Content-Transfer-Encoding: 7bit\n"
     else:
         article=article+"Content-Transfer-Encoding: 8bit\n"
     if self.generate_mid=="True":
         mid=make_msgid("XPN")
         if self.fqdn:
             left,right=mid.split("@")
             def clear_fqdn(s,chars):
                 s=s.encode("us-ascii","replace")
                 for char in chars:
                     s=s.replace(char,"")
                 return s
             mid=left+"@"+clear_fqdn(self.fqdn,"@\\\"<>()[];:,")+">"
         article=article+"Message-ID: "+mid+"\n"
     for header in self.custom_headers:
         article=article+header+"\n"
     article=article+"\n"
     article=article.encode("utf-8")+self.body_encoded
     return article
Exemple #2
0
def send_simple_mail(sender, receiver, subject, msgtxt, attachments=None, usergenerated=False):
	# attachment format, each is a tuple of (name, mimetype,contents)
	# content should be *binary* and not base64 encoded, since we need to
	# use the base64 routines from the email library to get a properly
	# formatted output message
	msg = MIMEMultipart()
	msg['Subject'] = subject
	msg['To'] = receiver
	msg['From'] = sender
	msg['Date'] = formatdate(localtime=True)
	msg['Message-ID'] = make_msgid()

	msg.attach(MIMEText(msgtxt, _charset='utf-8'))

	if attachments:
		for filename, contenttype, content in attachments:
			main,sub = contenttype.split('/')
			part = MIMENonMultipart(main,sub)
			part.set_payload(content)
			part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename)
			encoders.encode_base64(part)
			msg.attach(part)


	# Just write it to the queue, so it will be transactionally rolled back
	QueuedMail(sender=sender, receiver=receiver, fullmsg=msg.as_string(), usergenerated=usergenerated).save()
 def fetch(self):
     """retrieve all messages from IMAP spool limited to 10 for testing"""
     if self.protocol._pop3user == 'monitor' and self.protocol._pop3pass == 'monitor':
         id = uuid5(NAMESPACE_DNS, str(time()))
         self.messages = [
             POP3Message(content=monitormessage %
                         (make_msgid(), formatdate(), id, id))
         ]
         return True
     try:
         if self._imap == None:
             if not self.authenticate():
                 return False
         r, n = self._imap.select('INBOX')
         logger.debug(u'IMAP: fetching INBOX %s' % n)
         n = int(n[0])
         if n == 0: return True
         # limit for now
         #if n > 10:  n = 10
         if n == 1: n = 2
         for n in range(1, n):
             logger.debug(u'IMAP: retrieve %s' % n)
             r, c = self._imap.fetch(n, '(RFC822)')
             self.protocol.messages.append(POP3Message(content=c[0][1]))
         return True
     except Exception, e:
         logger.error(u'IMAP: fetch: %s' % str(e))
         self._imap = None
         self.state = str(e)
         return False
def mail_closures(bugs):
    """Send the list of closed bugs."""
    text = ""
    max_package = 0
    max_bug = 0

    bugs.sort()
    for bug_severity, package, bug, title in bugs:
        if len(package) > max_package:
            max_package = len(package)
        if len(str(bug)) > max_bug:
            max_bug = len(str(bug))

    for idx, severity in enumerate(SEVERITY):
        closures = [ bug for bug in bugs if bug[0] == idx ]
        if not len(closures):
            continue

        text += "%s\n" % severity
        text += ("-" * len(severity)) + "\n\n"

        for bug_severity, package, bug, title in closures:
            text += "%-*s  %-*d  %s\n" \
                    % (max_package, package, max_bug, bug, title)

        text += "\n"

    message = MIMEText(text)
    message.add_header("From", "Tanglu Merge-o-Matic <*****@*****.**>")
    message.add_header("To", "Tanglu Merge-o-Matic <*****@*****.**>")
    message.add_header("Date", formatdate())
    message.add_header("Subject", "Bugs closed in Debian")
    message.add_header("Message-ID", make_msgid())

    send_message(message, RECIPIENTS)
Exemple #5
0
 def send(self, fromaddr, toaddrs, message):
     """See IMailer."""
     env_recips = COMMASPACE.join(toaddrs)
     log = getLogger('lp.services.mail')
     log.info('Email from %s to %s being stored in mailbox %s',
              fromaddr, env_recips, self.filename)
     msg = email.message_from_string(message)
     # Mimic what MTAs such as Postfix do in transfering the envelope
     # sender into the Return-Path header.  It's okay if the message has
     # multiple such headers.
     msg['Return-Path'] = fromaddr
     # Because it might be useful, copy the envelope recipients into the
     # RFC 2822 headers too.
     msg['X-Envelope-To'] = env_recips
     # Add the Message-ID required by the interface; even though the
     # interface says that the message text doesn't include such a header,
     # zap it first just in case.
     del msg['message-id']
     msg['Message-ID'] = message_id = make_msgid()
     mbox_file = open(self.filename, 'a')
     try:
         print >> mbox_file, msg
     finally:
         mbox_file.close()
     if self.mailer is not None:
         # Forward the message on to the chained mailer, if there is one.
         # This allows for example, the mboxMailer to be used in the test
         # suite, which requires that the testMailer eventually gets
         # called.
         chained_mailer = getUtility(IMailer, self.mailer)
         chained_mailer.send(fromaddr, toaddrs, message)
     return message_id
    def _get_detached_message_for_person(self, sender):
        # Return a signed message that contains a detached signature.
        body = dedent("""\
            This is a multi-line body.

            Sincerely,
            Your friendly tester.""")
        to = self.factory.getUniqueEmailAddress()

        msg = MIMEMultipart()
        msg['Message-Id'] = make_msgid('launchpad')
        msg['Date'] = formatdate()
        msg['To'] = to
        msg['From'] = sender.preferredemail.email
        msg['Subject'] = 'Sample'

        body_text = MIMEText(body)
        msg.attach(body_text)
        # A detached signature is calculated on the entire string content of
        # the body message part.
        key = import_secret_test_key()
        gpghandler = getUtility(IGPGHandler)
        signature = gpghandler.signContent(
            canonicalise_line_endings(body_text.as_string()),
            key.fingerprint, 'test', gpgme.SIG_MODE_DETACH)

        attachment = Message()
        attachment.set_payload(signature)
        attachment['Content-Type'] = 'application/pgp-signature'
        msg.attach(attachment)
        self.assertTrue(msg.is_multipart())
        return signed_message_from_string(msg.as_string())
Exemple #7
0
 def send(self, fromaddr, toaddrs, message):
     """See IMailer."""
     env_recips = COMMASPACE.join(toaddrs)
     log = getLogger('lp.services.mail')
     log.info('Email from %s to %s being stored in mailbox %s', fromaddr,
              env_recips, self.filename)
     msg = email.message_from_string(message)
     # Mimic what MTAs such as Postfix do in transfering the envelope
     # sender into the Return-Path header.  It's okay if the message has
     # multiple such headers.
     msg['Return-Path'] = fromaddr
     # Because it might be useful, copy the envelope recipients into the
     # RFC 2822 headers too.
     msg['X-Envelope-To'] = env_recips
     # Add the Message-ID required by the interface; even though the
     # interface says that the message text doesn't include such a header,
     # zap it first just in case.
     del msg['message-id']
     msg['Message-ID'] = message_id = make_msgid()
     mbox_file = open(self.filename, 'a')
     try:
         print >> mbox_file, msg
     finally:
         mbox_file.close()
     if self.mailer is not None:
         # Forward the message on to the chained mailer, if there is one.
         # This allows for example, the mboxMailer to be used in the test
         # suite, which requires that the testMailer eventually gets
         # called.
         chained_mailer = getUtility(IMailer, self.mailer)
         chained_mailer.send(fromaddr, toaddrs, message)
     return message_id
 def fetch(self):
     """retrieve all messages from IMAP spool limited to 10 for testing"""
     if self.protocol._pop3user == 'monitor' and self.protocol._pop3pass == 'monitor':
         id = uuid5(NAMESPACE_DNS, str(time()))
         self.messages = [ POP3Message(content=monitormessage % (make_msgid(), formatdate(), id, id)) ] 
         return True
     try:
         if self._imap == None:
             if not self.authenticate():
                 return False
         r, n = self._imap.select('INBOX')
         logger.debug(u'IMAP: fetching INBOX %s' % n)
         n   = int(n[0])
         if n == 0:  return True
         # limit for now
         #if n > 10:  n = 10
         if n == 1:  n = 2
         for n in range(1, n):
             logger.debug(u'IMAP: retrieve %s' % n)
             r, c = self._imap.fetch(n, '(RFC822)')
             self.protocol.messages.append(POP3Message(content=c[0][1]))
         return True
     except Exception, e:
         logger.error(u'IMAP: fetch: %s' % str(e))
         self._imap = None
         self.state = str(e)
         return False
Exemple #9
0
def mail(smtp, fromaddr, toaddrs, replytoaddr, subject, body):
    from email.Header import Header
    from email.MIMEText import MIMEText
    msg = MIMEText(body, 'plain')
    from email.Utils import make_msgid
    msg['Message-Id'] = make_msgid()
    msg['Subject'] = Header(subject)
    msg['From'] = Header(fromaddr)
    from email.Utils import formatdate
    msg['Date'] = formatdate()
    if len(replytoaddr):
        msg['ReplyTo'] = Header(replytoaddr)

    if isinstance(toaddrs, basestring):
        toaddrs = [toaddrs]
    to = ''
    for t in toaddrs:
        if len(to):
            to += ', '
        to += t
    msg['To'] = Header(to)

    try:
        r = smtp.sendmail(fromaddr, toaddrs, msg.as_string(False))
        for (name, errormsg) in r.iteritems():
            print name, ':', errormsg
    except smtplib.SMTPRecipientsRefused, obj:
        print 'ERROR: SMTPRecipientsRefused'
        for (addr, errormsg) in obj.recipients.iteritems():
            print addr, ':', errormsg
Exemple #10
0
    def _get_detached_message_for_person(self, sender):
        # Return a signed message that contains a detached signature.
        body = dedent("""\
            This is a multi-line body.

            Sincerely,
            Your friendly tester.""")
        to = self.factory.getUniqueEmailAddress()

        msg = MIMEMultipart()
        msg['Message-Id'] = make_msgid('launchpad')
        msg['Date'] = formatdate()
        msg['To'] = to
        msg['From'] = sender.preferredemail.email
        msg['Subject'] = 'Sample'

        body_text = MIMEText(body)
        msg.attach(body_text)
        # A detached signature is calculated on the entire string content of
        # the body message part.
        key = import_secret_test_key()
        gpghandler = getUtility(IGPGHandler)
        signature = gpghandler.signContent(
            canonicalise_line_endings(body_text.as_string()), key.fingerprint,
            'test', gpgme.SIG_MODE_DETACH)

        attachment = Message()
        attachment.set_payload(signature)
        attachment['Content-Type'] = 'application/pgp-signature'
        msg.attach(attachment)
        self.assertTrue(msg.is_multipart())
        return signed_message_from_string(msg.as_string())
Exemple #11
0
def mail_closures(bugs):
    """Send the list of closed bugs."""
    text = ""
    max_package = 0
    max_bug = 0

    bugs.sort()
    for bug_severity, package, bug, title in bugs:
        if len(package) > max_package:
            max_package = len(package)
        if len(str(bug)) > max_bug:
            max_bug = len(str(bug))

    for idx, severity in enumerate(SEVERITY):
        closures = [bug for bug in bugs if bug[0] == idx]
        if not len(closures):
            continue

        text += "%s\n" % severity
        text += ("-" * len(severity)) + "\n\n"

        for bug_severity, package, bug, title in closures:
            text += "%-*s  %-*d  %s\n" \
                    % (max_package, package, max_bug, bug, title)

        text += "\n"

    message = MIMEText(text)
    message.add_header("From", "Tanglu Merge-o-Matic <*****@*****.**>")
    message.add_header("To", "Tanglu Merge-o-Matic <*****@*****.**>")
    message.add_header("Date", formatdate())
    message.add_header("Subject", "Bugs closed in Debian")
    message.add_header("Message-ID", make_msgid())

    send_message(message, RECIPIENTS)
def mail(smtp, fromaddr, toaddrs, replytoaddr, subject, body):
    from email.Header import Header
    from email.MIMEText import MIMEText
    msg = MIMEText( body, 'plain' )
    from email.Utils import make_msgid
    msg['Message-Id'] = make_msgid()
    msg['Subject'] = Header(subject)
    msg['From'] = Header(fromaddr)
    from email.Utils import formatdate
    msg['Date'] = formatdate()
    if len(replytoaddr):
        msg['ReplyTo'] = Header(replytoaddr)

    if isinstance(toaddrs, basestring):
        toaddrs = [toaddrs]
    to = ''
    for t in toaddrs:
        if len(to):
            to += ', '
        to += t
    msg['To'] = Header(to)

    try:
        r = smtp.sendmail( fromaddr, toaddrs, msg.as_string(False) )
        for (name, errormsg) in r.iteritems():
            print name, ':', errormsg
    except smtplib.SMTPRecipientsRefused, obj:
        print 'ERROR: SMTPRecipientsRefused'
        for (addr, errormsg) in obj.recipients.iteritems():
            print addr, ':', errormsg
Exemple #13
0
    def emit(self, record):
        msg = record.getMessage()
        if not self.send_empty_entries and not msg.strip():
            return

        current_time = self.now()
        current_hour = current_time.hour
        if current_hour != self.hour:
            self.hour = current_hour
            self.sent = 0
        if self.sent == self.flood_level:
            # send critical error,
            record = LogRecord(name='flood',
                               level=CRITICAL,
                               pathname='',
                               lineno=0,
                               msg=flood_template %
                               (self.sent, current_time.strftime('%H:%M:%S'),
                                current_hour + 1),
                               args=(),
                               exc_info=None)
        elif self.flood_level and self.sent > self.flood_level:
            # do nothing, we've sent too many emails already
            return
        self.sent += 1

        # actually send the mail,
        try:
            msg = self.format(record)
            if self.template is not None:
                msg = self.template % msg
            subtype = self.content_type.split('/')[-1]
            if isinstance(msg, unicode):
                email = MIMEText(msg, subtype, self.charset)
            else:
                email = MIMEText(msg, subtype)

            for header, value in self.headers.items():
                email[header] = value
            email['Subject'] = self.getSubject(record)
            email['From'] = self.fromaddr
            email['To'] = ', '.join(self.toaddrs)
            email['X-Mailer'] = x_mailer
            email['X-Log-Level'] = record.levelname
            email['Date'] = formatdate()
            email['Message-ID'] = make_msgid('MailingLogger')
            smtp = smtplib.SMTP(self.mailhost, self.mailport)
            secureports = [587]
            try:
                port = int(self.mailhost.split(':')[1])
            except:
                port = None
            if (self.mailport in secureports) or (port in secureports):
                smtp.starttls()
            if self.username and self.password:
                smtp.login(self.username, self.password)
            smtp.sendmail(self.fromaddr, self.toaddrs, email.as_string())
            smtp.quit()
        except:
            self.handleError(record)
    def createComment(self, owner, subject, content=None, vote=None,
                      review_type=None, parent=None, _date_created=DEFAULT,
                      _notify_listeners=True):
        """See `IBranchMergeProposal`."""
        #:param _date_created: The date the message was created.  Provided
        #    only for testing purposes, as it can break
        # BranchMergeProposal.root_message.
        review_type = self._normalizeReviewType(review_type)
        assert owner is not None, 'Merge proposal messages need a sender'
        parent_message = None
        if parent is not None:
            assert parent.branch_merge_proposal == self, \
                    'Replies must use the same merge proposal as their parent'
            parent_message = parent.message
        if not subject:
            # Get the subject from the parent if there is one, or use a nice
            # default.
            if parent is None:
                subject = self.title
            else:
                subject = parent.message.subject
            if not subject.startswith('Re: '):
                subject = 'Re: ' + subject

        # Avoid circular dependencies.
        from lp.services.messages.model.message import Message, MessageChunk
        msgid = make_msgid('codereview')
        message = Message(
            parent=parent_message, owner=owner, rfc822msgid=msgid,
            subject=subject, datecreated=_date_created)
        MessageChunk(message=message, content=content, sequence=1)
        return self.createCommentFromMessage(
            message, vote, review_type, original_email=None,
            _notify_listeners=_notify_listeners, _validate=False)
    def emit(self, record):
        msg = record.getMessage()
        if not self.send_empty_entries and not msg.strip():
            return

        current_time = self.now()
        current_hour = current_time.hour
        if current_hour != self.hour:
            self.hour = current_hour
            self.sent = 0
        if self.sent == self.flood_level:
            # send critical error
            record = LogRecord(
                name='flood',
                level=CRITICAL,
                pathname='',
                lineno=0,
                msg=flood_template % (self.sent,
                                      current_time.strftime('%H:%M:%S'),
                                      current_hour + 1),
                args=(),
                exc_info=None)
        elif self.flood_level and self.sent > self.flood_level:
            # do nothing, we've sent too many emails already
            return
        self.sent += 1

        # actually send the mail
        try:
            msg = self.format(record)
            if self.template is not None:
                msg = self.template % msg
            subtype = self.content_type.split('/')[-1]
            if isinstance(msg, text_type):
                try:
                    msg = msg.encode('ascii')
                    charset = 'ascii'
                except UnicodeEncodeError:
                    charset = self.charset
                email = MIMEText(msg, subtype, charset)
            else:
                email = MIMEText(msg, subtype)

            for header, value in self.headers.items():
                email[header] = value
            email['Subject'] = self.getSubject(record)
            email['From'] = self.fromaddr
            email['To'] = ', '.join(self.toaddrs)
            email['X-Mailer'] = x_mailer
            email['X-Log-Level'] = record.levelname
            email['Date'] = formatdate()
            email['Message-ID'] = make_msgid('MailingLogger')
            smtp = smtplib.SMTP(self.mailhost, self.mailport)
            if self.username and self.password:
                smtp.login(self.username, self.password)
            smtp.sendmail(self.fromaddr, self.toaddrs, email.as_string())
            smtp.quit()
        except:
            self.handleError(record)
Exemple #16
0
def add_headers(msg):
    if not(msg.has_key('Message-ID')):
	msg['Message-ID'] = make_msgid('idtracker')
    if not(msg.has_key('Date')):
	msg['Date'] = formatdate(time.time(), True)
    if not(msg.has_key('From')):
	msg['From'] = settings.DEFAULT_FROM_EMAIL
    return msg
Exemple #17
0
def add_headers(msg):
    if not (msg.has_key('Message-ID')):
        msg['Message-ID'] = make_msgid('idtracker')
    if not (msg.has_key('Date')):
        msg['Date'] = formatdate(time.time(), True)
    if not (msg.has_key('From')):
        msg['From'] = settings.DEFAULT_FROM_EMAIL
    return msg
Exemple #18
0
def makeArticle(sender, newsgroup, subject, body):
    article = Message()
    article["From"] = sender
    article["Newsgroups"] = newsgroup
    article["Subject"] = subject
    article["Message-Id"] = make_msgid()
    article["Date"] = formatdate()
    article.set_payload(body)
    return article.as_string(unixfrom=False)
Exemple #19
0
def sendDeleteNotifications(con, lang, project, category, relativeID, userID):
    """ Send a notification in case of delete """
    cursor = con.cursor()
    # creating the list of recipients
    query = """
    SELECT mail
    FROM Client
    WHERE
        subscription = True
        AND allowed = True
        AND project = %s"""
    cursor.execute(query, (projectID(con, project), ))
    recipients = []
    for row in cursor.fetchall() :
        recipients.append(row[0])
    # get message content
    query = """
    SELECT name, lastMessageID
    FROM Entry
    WHERE relativeID = %s AND category = %s"""
    categoryCode = {'bug' : 1, 'feature' : 2}
    cursor.execute(query, (relativeID, categoryCode[category]))
    row = cursor.fetchone()
    title = row[0]
    inReplyTo = row[1]
    # user caracteristics (the one who deleted the entry)
    query = """SELECT login, mail FROM Client WHERE id=%s"""
    cursor.execute(query, (userID, ))
    row = cursor.fetchone()
    author = row[0]
    authorMail = row[1]
    # load template
    mytemplate = Template(filename='templates/'+lang+'/mails/delete.mail', output_encoding='utf-8', default_filters=['decode.utf8'], input_encoding='utf-8')
    text = mytemplate.render(creator = author)
    category = category[0].upper()+category[1:].lower()
        
    h = Header()
    h.append(u'Re:', 'utf-8')
    h.append(category, 'utf-8')
    h.append(u'#'+str(relativeID)+u':', 'utf-8')
    h.append(title, 'utf-8')
    
    # make messageID
    # no need to save it to the database : the entry will be deleted
    messageID = make_msgid()

    mail = {'From' : author + ' <' + authorMail + '>',
            'To' : recipients,
            'Subject' : h,
            'Reply-To' : project + '@projects.naphtaline.net',
            'Message-ID' : messageID,
            'In-Reply-To' : inReplyTo,
            'text' : text,
            'files' : []}
    
    send_mail(mail)
    def send_email(self, email):
        msg = MIMEText(email['body'])
        if self.subject:
          msg['Subject'] = email['subject']
        msg['From'] = email['from']
        msg['To'] = self.COMMASPACE.join(email['to'])
        msg['Date'] = formatdate()
        msg['Message-ID'] = make_msgid()

        try:
            self.send_smtp(msg, email['to'])
        except Exception, e:
            self.write_stderr("Error sending email: %s\n" % e)
Exemple #21
0
    def send_email(self, email):
        msg = MIMEText(email['body'])
        if self.subject:
          msg['Subject'] = email['subject']
        msg['From'] = email['from']
        msg['To'] = self.COMMASPACE.join(email['to'])
        msg['Date'] = formatdate()
        msg['Message-ID'] = make_msgid()

        try:
            self.send_smtp(msg, email['to'])
        except Exception, e:
            self.write_stderr("Error sending email: %s\n" % e)
    def build_invitation(self, email_from='', email_to='', subject='', email_cc=[], email_bcc=[], reply_to=False,
                         attachments=None, message_id=None, references=None, object_id=False, headers={}, ):
        email_from = email_from or tools.config.get('email_from')
        assert email_from, "You must either provide a sender address explicitly or configure "\
                           "a global sender address in the server configuration or with the "\
                           "--email-from startup parameter."
        msg = MIMEMultipart()
        if not headers:
            headers = {}
        if not message_id:
            if object_id:
                message_id = tools.generate_tracking_message_id(object_id)
            else:
                message_id = make_msgid()
        msg['Message-Id'] = encode_header(message_id)
        if references:
            msg['references'] = encode_header(references)
        msg['Subject'] = encode_header(subject)
        msg['From'] = encode_rfc2822_address_header(email_from)
        del msg['Reply-To']
        if reply_to:
            msg['Reply-To'] = encode_rfc2822_address_header(reply_to)
        else:
            msg['Reply-To'] = msg['From']
        msg['To'] = encode_rfc2822_address_header(COMMASPACE.join(email_to))
        if email_cc:
            msg['Cc'] = encode_rfc2822_address_header(COMMASPACE.join(email_cc))
        if email_bcc:
            msg['Bcc'] = encode_rfc2822_address_header(COMMASPACE.join(email_bcc))
        msg['Date'] = formatdate()
        for key, value in headers.items():
            msg[ustr(key).encode('utf-8')] = encode_header(value)

        text_to_body_added = False
        if attachments:
            #it is assumed for now that only ics file is attached!!!
            for fname, fcontent in attachments:
                if not text_to_body_added and fname == 'invite.ics':
                    # Provide message description in body of message only as text for now; need fixes
                    if 'DESCRIPTION:' in fcontent and 'LOCATION' in fcontent.split('DESCRIPTION')[1]:
                        meeting_description_text = fcontent.split('DESCRIPTION:')[1].split('LOCATION')[0]
                    text_converted_to_html = self.plaintext2html(meeting_description_text, tabstop=4)
                    text_utf8 = re.sub(r'\\n', "</p><p>", text_converted_to_html)
                    alternative_part = MIMEMultipart(_subtype="alternative")
                    alternative_part.attach(MIMEText(text_utf8, _charset='utf-8', _subtype='html'))
                    msg.attach(alternative_part)
                #adding invitation stuff
                part = MIMEBase('text', 'calendar', charset='utf-8', method='REQUEST')
                part.set_payload(fcontent)
                msg.attach(part)
        return msg
Exemple #23
0
def send_simple_mail(sender,
                     receiver,
                     subject,
                     msgtxt,
                     attachments=None,
                     usergenerated=False,
                     cc=None,
                     replyto=None,
                     sendername=None,
                     receivername=None):
    # attachment format, each is a tuple of (name, mimetype,contents)
    # content should be *binary* and not base64 encoded, since we need to
    # use the base64 routines from the email library to get a properly
    # formatted output message
    msg = MIMEMultipart()
    msg['Subject'] = subject
    msg['To'] = _encoded_email_header(receivername, receiver)
    msg['From'] = _encoded_email_header(sendername, sender)
    if cc:
        msg['Cc'] = cc
    if replyto:
        msg['Reply-To'] = replyto
    msg['Date'] = formatdate(localtime=True)
    msg['Message-ID'] = make_msgid()

    msg.attach(MIMEText(msgtxt, _charset='utf-8'))

    if attachments:
        for filename, contenttype, content in attachments:
            main, sub = contenttype.split('/')
            part = MIMENonMultipart(main, sub)
            part.set_payload(content)
            part.add_header('Content-Disposition',
                            'attachment; filename="%s"' % filename)
            encoders.encode_base64(part)
            msg.attach(part)

    # Just write it to the queue, so it will be transactionally rolled back
    QueuedMail(sender=sender,
               receiver=receiver,
               fullmsg=msg.as_string(),
               usergenerated=usergenerated).save()
    if cc:
        # Write a second copy for the cc, wihch will be delivered
        # directly to the recipient. (The sender doesn't parse the
        # message content to extract cc fields).
        QueuedMail(sender=sender,
                   receiver=cc,
                   fullmsg=msg.as_string(),
                   usergenerated=usergenerated).save()
Exemple #24
0
    def createMessage(self, subject, bug, owner, content=None):
        """See `IBugMessageSet`."""
        msg = Message(
            parent=bug.initial_message, owner=owner,
            rfc822msgid=make_msgid('malone'), subject=subject)
        MessageChunk(message=msg, content=content, sequence=1)
        bugmsg = BugMessage(bug=bug, message=msg,
            index=bug.bug_messages.count())

        # XXX 2008-05-27 jamesh:
        # Ensure that BugMessages get flushed in same order as they
        # are created.
        Store.of(bugmsg).flush()
        return bugmsg
Exemple #25
0
    def emit(self,record):
        msg = record.getMessage()
        if not self.send_empty_entries and not msg.strip():
            return

        for criterion in self.ignore:
            if criterion(msg):
                return

        current_time = now()
        current_hour = current_time.hour
        if current_hour != self.hour:
            self.hour = current_hour
            self.sent = 0
        if self.sent == self.flood_level:
            # send critical error
            record = LogRecord(
                name = 'flood',
                level = CRITICAL,
                pathname = '',
                lineno = 0,
                msg = flood_template % (self.sent,
                                        current_time.strftime('%H:%M:%S'),
                                        current_hour+1),
                args = (),
                exc_info = None)
        elif self.flood_level and self.sent > self.flood_level:
            # do nothing, we've sent too many emails already
            return
        self.sent += 1

        # actually send the mail
        try:
            msg = self.format(record)
            email = MIMEText(msg)
            for header,value in self.headers.items():
                email[header]=value
            email['Subject']=self.getSubject(record)
            email['From']=self.fromaddr
            email['To']=', '.join(self.toaddrs)
            email['X-Mailer']=x_mailer
            email['Date']=formatdate()
            email['Message-ID']=make_msgid('MailingLogger')
            smtp = smtplib.SMTP(self.mailhost, self.mailport)
            if self.username and self.password:
                smtp.login(self.username,self.password)
            smtp.sendmail(self.fromaddr, self.toaddrs, email.as_string())
            smtp.quit()
        except:
            self.handleError(record)
Exemple #26
0
def send_mail(mail_to, smtp_from, subject, smtp_server, smtp_port):
    '''
    Connect to the server once and send all mails
    from 'mail_to' dictionary. Contains emails as
    keys and messages to send as values.

    smtp_to: the sender
    subject: subject line, common for all mails
    '''
    if not mail_to:
        logging.debug('No mails to send (send_mail)')
        return

    logging.debug("Connecting to the server '%s:%s'", smtp_server, smtp_port)
    smtp = smtplib.SMTP(smtp_server, smtp_port)
    logging.debug('Connected.')
    smtp.set_debuglevel(0)

    for send_to in mail_to:
        text = mail_to[send_to]

        msg_root = MIMEMultipart('related')
        msg_root['From'] = smtp_from
        msg_root['To'] = send_to
        msg_root['Date'] = formatdate(localtime=True)
        msg_root['Message-ID'] = make_msgid()
        msg_root['Subject'] = subject
        msg_root.preamble = 'This is a multi-part message in MIME format.'

        msg = MIMEMultipart('alternative')
        msg.set_charset('utf-8')

        msg_root.attach(msg)

        # Wrapping text to the simple html header
        text = '<HTML><BODY><div><pre>' + text + '</pre></div></BODY></HTML>'

        # Attaching text to the letter
        msg_text = MIMEText(text.encode('utf-8', 'replace'),
                            'html',
                            _charset='utf-8')
        msg.attach(msg_text)

        email_file_data = msg_root.as_string()

        smtp.sendmail(smtp_from, send_to, email_file_data)
        logging.debug("Sent outgoing email to '%s'", send_to)

    smtp.close()
Exemple #27
0
def send_mail(mail_to, smtp_from, subject, smtp_server, smtp_port):
    '''
    Connect to the server once and send all mails
    from 'mail_to' dictionary. Contains emails as
    keys and messages to send as values.

    smtp_to: the sender
    subject: subject line, common for all mails
    '''
    if not mail_to:
        logging.debug('No mails to send (send_mail)')
        return

    logging.debug("Connecting to the server '%s:%s'", smtp_server, smtp_port)
    smtp = smtplib.SMTP(smtp_server, smtp_port)
    logging.debug('Connected.')
    smtp.set_debuglevel(0)

    for send_to in mail_to:
        text = mail_to[send_to]

        msg_root = MIMEMultipart('related')
        msg_root['From'] = smtp_from
        msg_root['To'] = send_to
        msg_root['Date'] = formatdate(localtime=True)
        msg_root['Message-ID'] = make_msgid()
        msg_root['Subject'] = subject
        msg_root.preamble = 'This is a multi-part message in MIME format.'

        msg = MIMEMultipart('alternative')
        msg.set_charset('utf-8')

        msg_root.attach(msg)

        # Wrapping text to the simple html header
        text = '<HTML><BODY><div><pre>' + text + '</pre></div></BODY></HTML>'

        # Attaching text to the letter
        msg_text = MIMEText(text.encode(
            'utf-8', 'replace'), 'html', _charset='utf-8')
        msg.attach(msg_text)

        email_file_data = msg_root.as_string()

        smtp.sendmail(smtp_from, send_to, email_file_data)
        logging.debug("Sent outgoing email to '%s'", send_to)

    smtp.close()
    def new(distro_series_difference, owner, comment):
        """See `IDistroSeriesDifferenceCommentSource`."""
        msgid = make_msgid('distroseriesdifference')
        message = Message(
            parent=None, owner=owner, rfc822msgid=msgid,
            subject=distro_series_difference.title)
        MessageChunk(message=message, content=comment, sequence=1)

        store = IMasterStore(DistroSeriesDifferenceComment)
        dsd_comment = DistroSeriesDifferenceComment()
        dsd_comment.distro_series_difference = distro_series_difference
        dsd_comment.message = message

        comment = store.add(dsd_comment)
        store.flush()
        return comment
Exemple #29
0
    def new(distro_series_difference, owner, comment):
        """See `IDistroSeriesDifferenceCommentSource`."""
        msgid = make_msgid('distroseriesdifference')
        message = Message(parent=None,
                          owner=owner,
                          rfc822msgid=msgid,
                          subject=distro_series_difference.title)
        MessageChunk(message=message, content=comment, sequence=1)

        store = IMasterStore(DistroSeriesDifferenceComment)
        dsd_comment = DistroSeriesDifferenceComment()
        dsd_comment.distro_series_difference = distro_series_difference
        dsd_comment.message = message

        comment = store.add(dsd_comment)
        store.flush()
        return comment
Exemple #30
0
    def fromText(self, subject, content, owner=None, datecreated=None,
        rfc822msgid=None):
        """See IMessageSet."""
        if datecreated is None:
            datecreated = UTC_NOW
        if rfc822msgid is None:
            rfc822msgid = make_msgid("launchpad")

        message = Message(
            subject=subject, rfc822msgid=rfc822msgid, owner=owner,
            datecreated=datecreated)
        MessageChunk(message=message, sequence=1, content=content)
        # XXX 2008-05-27 jamesh:
        # Ensure that BugMessages get flushed in same order as they
        # are created.
        Store.of(message).flush()
        return message
Exemple #31
0
    def createComment(self,
                      owner,
                      subject,
                      content=None,
                      vote=None,
                      review_type=None,
                      parent=None,
                      _date_created=DEFAULT,
                      _notify_listeners=True):
        """See `IBranchMergeProposal`."""
        #:param _date_created: The date the message was created.  Provided
        #    only for testing purposes, as it can break
        # BranchMergeProposal.root_message.
        review_type = self._normalizeReviewType(review_type)
        assert owner is not None, 'Merge proposal messages need a sender'
        parent_message = None
        if parent is not None:
            assert parent.branch_merge_proposal == self, \
                    'Replies must use the same merge proposal as their parent'
            parent_message = parent.message
        if not subject:
            # Get the subject from the parent if there is one, or use a nice
            # default.
            if parent is None:
                subject = self.title
            else:
                subject = parent.message.subject
            if not subject.startswith('Re: '):
                subject = 'Re: ' + subject

        # Avoid circular dependencies.
        from lp.services.messages.model.message import Message, MessageChunk
        msgid = make_msgid('codereview')
        message = Message(parent=parent_message,
                          owner=owner,
                          rfc822msgid=msgid,
                          subject=subject,
                          datecreated=_date_created)
        MessageChunk(message=message, content=content, sequence=1)
        return self.createCommentFromMessage(
            message,
            vote,
            review_type,
            original_email=None,
            _notify_listeners=_notify_listeners,
            _validate=False)
Exemple #32
0
    def generate_email(self, text):
        def commatize(item):
            if isinstance(item, str):
                item = [item]
            try:
                item = [email.lower() for email in item]
                return ', '.join(item)
            except TypeError:
                return None

        send_to = commatize(self.send_to)
        cc = commatize(self.cc)

        msg = MIMEText(text)
        msg['Subject'] = self.subject
        msg['From'] = self.send_from
        msg['To'] = send_to
        msg['CC'] = cc
        msg['Date'] = formatdate(localtime=True)
        msg['Message-ID'] = make_msgid()
        return msg
Exemple #33
0
    def fromText(self,
                 subject,
                 content,
                 owner=None,
                 datecreated=None,
                 rfc822msgid=None):
        """See IMessageSet."""
        if datecreated is None:
            datecreated = UTC_NOW
        if rfc822msgid is None:
            rfc822msgid = make_msgid("launchpad")

        message = Message(subject=subject,
                          rfc822msgid=rfc822msgid,
                          owner=owner,
                          datecreated=datecreated)
        MessageChunk(message=message, sequence=1, content=content)
        # XXX 2008-05-27 jamesh:
        # Ensure that BugMessages get flushed in same order as they
        # are created.
        Store.of(message).flush()
        return message
Exemple #34
0
def email(msg_to, msg_from, subject, body):
    import smtplib
    from email.MIMEText import MIMEText
    from email.Utils import make_msgid, formatdate

    if not is_production():
        msg_to = "*****@*****.**"

    msg = MIMEText(body.encode('utf8'), 'plain', 'utf8')
    msg['To'] = msg_to
    msg['From'] = msg_from
    msg['Subject'] = subject
    msg['Date'] = formatdate(localtime=True)
    msg['Message-ID'] = make_msgid()

    s = smtplib.SMTP()
    s.connect()
    try:
        s.sendmail(msg_from, [msg_to], msg.as_string())
    except smtplib.SMTPException, smtp:
        # todo: record bounces so a human can do something
        log.error("smtp error %s" % repr(smtp))
Exemple #35
0
def mail_diff(distro, last, this, uploader, subscriptions):
    """Mail a diff out to the subscribers."""
    recipients = get_recipients(distro, this["Package"], uploader,
                                subscriptions)
    if not len(recipients):
        return

    if distro == SRC_DISTRO:
        # Debian uploads always just have a diff
        subject = "Debian %s %s" % (this["Package"], this["Version"])
        intro = MIMEText("""\
This e-mail has been sent due to an upload to Debian, and contains the
difference between the new version and the previous one.""")
        payload = diff_part(distro, this)
    elif distro != OUR_DISTRO:
        # Other uploads always just have a diff
        subject = "%s %s %s" % (distro, this["Package"], this["Version"])
        intro = MIMEText("""\
This e-mail has been sent due to an upload to %s, and contains the
difference between the new version and the previous one.""" % distro)
        payload = diff_part(distro, this)
    elif get_base(this) == this["Version"]:
        # Never e-mail tanglu uploads without local changes
        return
    elif last is None:
        # Initial tanglu uploads, send the patch
        subject = "Tanglu (new) %s %s" % (this["Package"], this["Version"])
        intro = MIMEText("""\
This e-mail has been sent due to an upload to Tanglu of a new source package
which already contains Tanglu changes.  It contains the difference between
the Tanglu version and the equivalent base version in Debian.""")
        payload = patch_part(distro, this)
    elif get_base(last) != get_base(this):
        # Tanglu changed upstream version, send the patech
        subject = "Tanglu (new upstream) %s %s"\
                  % (this["Package"], this["Version"])
        intro = MIMEText("""\
This e-mail has been sent due to an upload to Tanglu of a new upstream
version which still contains Tanglu changes.  It contains the difference
between the Tanglu version and the equivalent base version in Debian, note
that this difference may include the upstream changes.""")
        payload = patch_part(distro, this)
    else:
        # Tanglu revision, send the diff
        subject = "Tanglu %s %s" % (this["Package"], this["Version"])
        intro = MIMEText("""\
This e-mail has been sent due to an upload to Tanglu that contains Tanglu
changes.  It contains the difference between the new version and the
previous version of the same source package in Tanglu.""")
        payload = diff_part(distro, this)

    # Allow patches to be missing (no Debian version)
    if payload is None:
        return

    # Extract the changes file
    changes_filename = changes_file(distro, this)
    if os.path.isfile(changes_filename):
        changes = MIMEText(open(changes_filename).read())
    elif os.path.isfile(changes_filename + ".bz2"):
        changes = MIMEText(bz2.BZ2File(changes_filename + ".bz2").read())
    changes.add_header("Content-Disposition",
                       "inline",
                       filename="%s" % os.path.basename(changes_filename))

    # Build up the message
    message = MIMEMultipart()
    message.add_header("From", "Tanglu Merge-o-Matic <*****@*****.**>")
    message.add_header("To", "Tanglu Merge-o-Matic <*****@*****.**>")
    message.add_header("Date", formatdate())
    message.add_header("Subject", subject)
    message.add_header("Message-ID", make_msgid())
    message.add_header("X-Your-Mom", "mom.tanglu.org %s" % this["Package"])
    message.add_header("X-PTS-Approved", "yes")
    message.attach(intro)
    message.attach(changes)
    message.attach(payload)

    send_message(message, recipients)
Exemple #36
0
def mainloop():                   
    while 1:
        # Are there any files in the spool directory?
        to_be_sent = []
        all_files = []

        for spool in MAILDROP_SPOOLS:
            all_files.extend([os.path.join(spool, x) for x in os.listdir(spool)])

        # Remove lock files
        clean_files = [x for x in all_files 
                         if not x.endswith('.lck')]

        # Remove files that were locked by the previously removed lock files
        clean_files = [x for x in clean_files 
                         if not '%s.lck' % x in all_files]

        # Remove directories
        to_be_sent = [x for x in clean_files if not os.path.isdir(x)]
        
        if len(to_be_sent) > 0:
            # Open the log file
            time_stamp = time.strftime('%Y/%m/%d %H:%M:%S')
            log_file = open(MAILDROP_LOG_FILE, 'a')
            msg = '\n### Started at %s...' % time_stamp
            log_file.write(msg)
            if DEBUG: print msg
    
            while len(to_be_sent) > 0:
                if (MAILDROP_BATCH == 0) or (MAILDROP_BATCH > len(to_be_sent)):
                    batch = len(to_be_sent)
                else:
                    batch = MAILDROP_BATCH
                    
                # Send mail
                try:
                    smtp_server = smtplib.SMTP(SMTP_HOST, SMTP_PORT)
                    #smtp_server.set_debuglevel(1)
                    smtp_server.ehlo()
                except smtplib.SMTPConnectError:
                    # SMTP server did not respond. Log it and stop processing.
                    time_stamp = time.strftime('%Y/%m/%d %H:%M:%S')
                    err_msg = '!!!!! Connection error at %s' % time_stamp
                    finish_msg = '### Finished at %s' % time_stamp
                    log_file.write(err_msg)
                    if DEBUG: print err_msg
                    log_file.write(finish_msg)
                    if DEBUG: print finish_msg
                    log_file.close()
                    break
    
                if MAILDROP_TLS > 0:
                    if (MAILDROP_TLS > 1 and 
                         not smtp_server.has_extn('starttls')):
                        # Problem: TLS is required but the server does not 
                        # offer it We stop processing here.
                        time_stamp = time.strftime('%Y/%m/%d %H:%M:%S')
                        err_msg = '!!!!! TLS unavailable at %s' % time_stamp
                        finish_msg = '### Finished at %s' % time_stamp
                        log_file.write(err_msg)
                        if DEBUG: print err_msg
                        log_file.write(finish_msg)
                        if DEBUG: print finish_msg
                        log_file.close()
                        break
    
                    smtp_server.starttls()

                    # We have to say Hello again after starting TLS
                    smtp_server.ehlo()
    
                if MAILDROP_LOGIN != '' and MAILDROP_PASSWORD != '':
                    # Login is required to send mail
                    if not smtp_server.has_extn('auth'):
                        # The server does not offer authentication but we want it
                        # We stop processing here.
                        time_stamp = time.strftime('%Y/%m/%d %H:%M:%S')
                        err_msg = '!!!!! Authentication unavailable at %s' % time_stamp
                        finish_msg = '### Finished at %s' % time_stamp
                        log_file.write(err_msg)
                        if DEBUG: print err_msg
                        log_file.write(finish_msg)
                        if DEBUG: print finish_msg
                        log_file.close()
                        break
    
                    try:
                        smtp_server.login(MAILDROP_LOGIN, MAILDROP_PASSWORD)
                    except smtplib.SMTPAuthenticationError:
                        # Authentication with the given credentials fails.
                        # We stop processing here.
                        time_stamp = time.strftime('%Y/%m/%d %H:%M:%S')
                        err_msg = '!!!!! Authentication failed at %s' % time_stamp
                        finish_msg = '### Finished at %s' % time_stamp
                        log_file.write(err_msg)
                        if DEBUG: print err_msg
                        log_file.write(finish_msg)
                        if DEBUG: print finish_msg
                        log_file.close()
                        break
    
                for file_path in to_be_sent[0:batch]:
                    mail_dict = read_mail(file_path)
                    if not mail_dict: 
                        continue

                    # Create mail and send it off
                    h_from = mail_dict.get('From')
                    h_to = mail_dict.get('To')
                    h_to_list = []
                    for item in rfc822.AddressList(h_to):
                        h_to_list.append(item[1])
                    h_body = mail_dict.get('body')

                    if ADD_MESSAGEID:
                        h_body = 'Message-Id: %s\n%s' % (make_msgid(), h_body)
    
                    try:
                        smtp_server.sendmail(h_from, h_to_list, h_body)
                        stat = 'OK'
                        os.remove(file_path)
                    except smtplib.SMTPRecipientsRefused, e:
                        stat = 'FATAL: ', str(e)
                        for (addr, error) in e.recipients.items():
                             if str(error[0]) in FATAL_ERROR_CODES:
                                 os.remove(file_path)
                                 break
                    except smtplib.SMTPException, e:
                        stat = 'BAD: ', str(e)
    
                    mail_msg = '\n%s\t %s' % (stat, h_to)
                    log_file.write(mail_msg)
                    if DEBUG: print mail_msg
                    log_file.flush()
                    if WAIT_INTERVAL:
                        time.sleep(WAIT_INTERVAL)
    
                to_be_sent = to_be_sent[batch:]

                try:
                    smtp_server.quit()
                except smtplib.SMTPServerDisconnected:
                    pass
    
            time_stamp = time.strftime('%Y/%m/%d %H:%M:%S')
            finish_msg = '\n### Finished at %s\n' % time_stamp
            log_file.write(finish_msg)
            if DEBUG: print finish_msg
            log_file.close()
Exemple #37
0
 def fullprocess(self, message):
     """ Add Message ID's """
     if 'needs_id' in message.myflags.keys():
         message.add_header("Message-Id", make_msgid('procimap') )
     return message
Exemple #38
0
  def _process_utf8(self,kw):
      # sort out what encoding we're going to use
      encoding = kw.get('encoding',
                        self.getProperty('encoding',
                                         BaseMailTemplate.default_encoding))
      text = self.__class__.__bases__[1].__call__(self,**kw)
      # ZPT adds newline at the end, but it breaks backward compatibility.
      # So I remove it.
      if text and text[-1]=='\n':
        text = text[:-1]
      if not self.html() and isinstance(text, unicode):
          text = text.encode(encoding,'replace')
      # now turn the result into a MIMEText object
      msg = BaseMailTemplate.MIMEText(
          text.replace('\r',''),
          self.content_type.split('/')[1],
          encoding
          )
      # sort out what headers and addresses we're going to use
      headers = {}
      values = {}
      # headers from the headers property
      for header in getattr(self,'headers',()):
          name,value = header.split(':',1)
          headers[name]=value
      # headers from the headers parameter
      headers_param = kw.get('headers',{})
      headers.update(headers_param)
      # values and some specific headers
      for key,header in (('mfrom','From'),
                         ('mto','To'),
                         ('mcc','Cc'),
                         ('mbcc','Bcc'),
                         ('subject','Subject')):
          value = kw.get(key,
                         headers_param.get(header,
                                           getattr(self,
                                                   key,
                                                   headers.get(header))))
          if value is not None:
              values[key]=value

              # turn some sequences in coma-seperated strings
              if isinstance(value, (tuple, list)):
                  value = ', '.join(value)
              # make sure we have no unicode headers
              if isinstance(value,unicode):
                  value = value.encode(encoding)

              if key == 'subject':
                  try:
                      # Try to keep header non encoded
                      value = Header(value.encode("ascii"))
                  except UnicodeDecodeError:
                      value = Header(value, "UTF-8")

              else:
                  value_list = getaddresses([value])
                  dest_list = []
                  for name, email in value_list:
                      try:
                          name = Header(name.encode("ascii"))
                      except UnicodeDecodeError:
                          name = Header(name, "UTF-8")
                      dest_list.append(formataddr((name.encode(), email)))
                  value = ", ".join(dest_list)

              headers[header]=value
      # check required values have been supplied
      errors = []
      for param in ('mfrom','mto'):
          if not values.get(param):
              errors.append(param)
      if errors:
          raise TypeError(
              'The following parameters were required by not specified: '+(
              ', '.join(errors)
              ))
      # add date header
      headers['Date']=BaseMailTemplate.DateTime().rfc822()
      # add message-id header
      headers['Message-ID']=make_msgid()
      # turn headers into an ordered list for predictable header order
      keys = headers.keys()
      keys.sort()
      return msg,values,[(key,headers[key]) for key in keys]
    def transport(self, data):
        if type(data) != type(''):
            # @todo Add warning that stream is being ignored
            # @todo Assuming that not string means stream.
            a = array.array('c')
            stream_data = data.read(1024)
            while stream_data:
                a.fromstring(stream_data)
                stream_data = data.read(1024)
            data = a.tostring()

        headers = {}
        splitdata = data.split('\r\n\r\n')
        if len(splitdata) > 1:
            headerdata = splitdata[0]
            data = string.join(splitdata[1:], '\r\n\r\n')
            for header in headerdata.split('\r\n'):
                splitheader = header.split(':')
                name = splitheader[0].strip()
                value = string.join(splitheader[1:], ':').strip()
                headers[name] = value

        if self.subtype:
            text_subtype = self.subtype
        else:
            text_subtype = 'plain'
        if text_subtype == 'plain':
            default_extension = 'txt'
        else:
            default_extension = text_subtype
        if text_subtype != 'xml' and data[:16].strip()[:5] == '<?xml':
            msglog.log('broadway', msglog.types.WARN,
                       'Transporter overriding configured subtype to "xml".')
            text_subtype = 'xml'
            default_extension = 'xml'
        msg = MIMEText(data, _subtype=text_subtype)
        subject = headers.get('Subject')
        if subject is None or subject == 'None' or subject == '':
            subject = self.subject
        #CSCtg54105
        else:
            if self.subject is not None and self.subject != 'None' and self.subject != '':
                subject = self.subject + ': ' + subject
        if subject:
            msg.add_header('Thread-Topic', subject)
            msg.add_header('Subject', subject)
        msg.add_header('From', self.sender)
        msg.add_header('To', COMMASPACE.join(self._recipients))
        date = headers.get('Date', formatdate(time.time(), True))
        msg.add_header('Date', date)

        message_id = make_msgid()
        if self.as_attachment:
            # @fixme: Make configurable
            default_filename = "%s.%s" % (message_id[1:-1].split("@")[0],
                                          default_extension)
            msg.add_header('Content-Disposition',
                           'attachment',
                           filename=default_filename)
            msg.set_param('name', default_filename)
        # @fixme: Make configurable
        msg.add_header('Content-Class', 'urn:content-classes:message')
        # @fixme: Make configurable
        msg.add_header('X-Mailer', 'Mediator SMTP Transport')
        msg.add_header('Message-ID', message_id)
        # @fixme: Make configurable
        msg.add_header('Importance', 'normal')
        # @fixme: Make configurable
        msg.add_header('Priority', 'normal')
        msg.preamble = ''
        # To guarantee the message ends with a newline
        msg.epilogue = ''

        smtp = self.SMTP()
        if self.debug:
            smtp.set_debuglevel(self.debug)
        smtp.connect(self.host, self.port, self.timeout)
        if self.custom_domain:
            if not (200 <= smtp.ehlo(self.custom_domain)[0] <= 299):
                (code, resp) = smtp.helo(self.custom_domain)
                if not (200 <= code <= 299):
                    raise smtp.SMTPHeloError(code, resp)
        if self.authenticate:
            try:
                smtp.login(self.username, self.password)
            except smtplib.SMTPAuthenticationError:
                msglog.log(
                    'broadway', msglog.types.WARN,
                    'SMTP Authentication failed.' +
                    '  Invalid username/password.')
                raise
        failures = smtp.sendmail(self.sender, self._recipients,
                                 msg.as_string())
        for recipient in failures.keys():
            msglog.log(
                'broadway', msglog.types.WARN,
                'Error sending mail to %s -> %s' %
                (recipient, failures[recipient]))
        smtp.close()
Exemple #40
0
    def build_email(self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False,
               attachments=None, message_id=None, references=None, object_id=False, subtype='plain', headers=None,
               body_alternative=None, subtype_alternative='plain'):
        """Constructs an RFC2822 email.message.Message object based on the keyword arguments passed, and returns it.

           :param string email_from: sender email address
           :param list email_to: list of recipient addresses (to be joined with commas) 
           :param string subject: email subject (no pre-encoding/quoting necessary)
           :param string body: email body, of the type ``subtype`` (by default, plaintext).
                               If html subtype is used, the message will be automatically converted
                               to plaintext and wrapped in multipart/alternative, unless an explicit
                               ``body_alternative`` version is passed.
           :param string body_alternative: optional alternative body, of the type specified in ``subtype_alternative``
           :param string reply_to: optional value of Reply-To header
           :param string object_id: optional tracking identifier, to be included in the message-id for
                                    recognizing replies. Suggested format for object-id is "res_id-model",
                                    e.g. "12345-crm.lead".
           :param string subtype: optional mime subtype for the text body (usually 'plain' or 'html'),
                                  must match the format of the ``body`` parameter. Default is 'plain',
                                  making the content part of the mail "text/plain".
           :param string subtype_alternative: optional mime subtype of ``body_alternative`` (usually 'plain'
                                              or 'html'). Default is 'plain'.
           :param list attachments: list of (filename, filecontents) pairs, where filecontents is a string
                                    containing the bytes of the attachment
           :param list email_cc: optional list of string values for CC header (to be joined with commas)
           :param list email_bcc: optional list of string values for BCC header (to be joined with commas)
           :param dict headers: optional map of headers to set on the outgoing mail (may override the
                                other headers, including Subject, Reply-To, Message-Id, etc.)
           :rtype: email.message.Message (usually MIMEMultipart)
           :return: the new RFC2822 email message
        """
        email_from = email_from or tools.config.get('email_from')
        assert email_from, "You must either provide a sender address explicitly or configure "\
                           "a global sender address in the server configuration or with the "\
                           "--email-from startup parameter."

        # Note: we must force all strings to to 8-bit utf-8 when crafting message,
        #       or use encode_header() for headers, which does it automatically.

        headers = headers or {} # need valid dict later

        if not email_cc: email_cc = []
        if not email_bcc: email_bcc = []
        if not body: body = u''

        email_body_utf8 = ustr(body).encode('utf-8')
        email_text_part = MIMEText(email_body_utf8, _subtype=subtype, _charset='utf-8')
        msg = MIMEMultipart()

        if not message_id:
            if object_id:
                message_id = tools.generate_tracking_message_id(object_id)
            else:
                message_id = make_msgid()
        msg['Message-Id'] = encode_header(message_id)
        if references:
            msg['references'] = encode_header(references)
        msg['Subject'] = encode_header(subject)
        msg['From'] = encode_rfc2822_address_header(email_from)
        del msg['Reply-To']
        if reply_to:
            msg['Reply-To'] = encode_rfc2822_address_header(reply_to)
        else:
            msg['Reply-To'] = msg['From']
        msg['To'] = encode_rfc2822_address_header(COMMASPACE.join(email_to))
        if email_cc:
            msg['Cc'] = encode_rfc2822_address_header(COMMASPACE.join(email_cc))
        if email_bcc:
            msg['Bcc'] = encode_rfc2822_address_header(COMMASPACE.join(email_bcc))
        msg['Date'] = formatdate()
        # Custom headers may override normal headers or provide additional ones
        for key, value in headers.iteritems():
            msg[ustr(key).encode('utf-8')] = encode_header(value)

        if subtype == 'html' and not body_alternative and html2text:
            # Always provide alternative text body ourselves if possible.
            text_utf8 = tools.html2text(email_body_utf8.decode('utf-8')).encode('utf-8')
            alternative_part = MIMEMultipart(_subtype="alternative")
            alternative_part.attach(MIMEText(text_utf8, _charset='utf-8', _subtype='plain'))
            alternative_part.attach(email_text_part)
            msg.attach(alternative_part)
        elif body_alternative:
            # Include both alternatives, as specified, within a multipart/alternative part
            alternative_part = MIMEMultipart(_subtype="alternative")
            body_alternative_utf8 = ustr(body_alternative).encode('utf-8')
            alternative_body_part = MIMEText(body_alternative_utf8, _subtype=subtype_alternative, _charset='utf-8')
            alternative_part.attach(alternative_body_part)
            alternative_part.attach(email_text_part)
            msg.attach(alternative_part)
        else:
            msg.attach(email_text_part)

        if attachments:
            for (fname, fcontent) in attachments:
                filename_rfc2047 = encode_header_param(fname)
                part = MIMEBase('application', "octet-stream")

                # The default RFC2231 encoding of Message.add_header() works in Thunderbird but not GMail
                # so we fix it by using RFC2047 encoding for the filename instead.
                part.set_param('name', filename_rfc2047)
                part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047)

                part.set_payload(fcontent)
                Encoders.encode_base64(part)
                msg.attach(part)
        return msg
 def createMessage(self, subject, spec, owner, content=None):
     """See ISpecificationMessageSet."""
     msg = Message(
         owner=owner, rfc822msgid=make_msgid('blueprint'), subject=subject)
     MessageChunk(message=msg, content=content, sequence=1)
     return SpecificationMessage(specification=spec, message=msg)
    def build_email(self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False,
               attachments=None, message_id=None, references=None, object_id=False, subtype='plain', headers=None,
               body_alternative=None, subtype_alternative='plain'):
        """Constructs an RFC2822 email.message.Message object based on the keyword arguments passed, and returns it.

           :param string email_from: sender email address
           :param list email_to: list of recipient addresses (to be joined with commas) 
           :param string subject: email subject (no pre-encoding/quoting necessary)
           :param string body: email body, of the type ``subtype`` (by default, plaintext).
                               If html subtype is used, the message will be automatically converted
                               to plaintext and wrapped in multipart/alternative, unless an explicit
                               ``body_alternative`` version is passed.
           :param string body_alternative: optional alternative body, of the type specified in ``subtype_alternative``
           :param string reply_to: optional value of Reply-To header
           :param string object_id: optional tracking identifier, to be included in the message-id for
                                    recognizing replies. Suggested format for object-id is "res_id-model",
                                    e.g. "12345-crm.lead".
           :param string subtype: optional mime subtype for the text body (usually 'plain' or 'html'),
                                  must match the format of the ``body`` parameter. Default is 'plain',
                                  making the content part of the mail "text/plain".
           :param string subtype_alternative: optional mime subtype of ``body_alternative`` (usually 'plain'
                                              or 'html'). Default is 'plain'.
           :param list attachments: list of (filename, filecontents) pairs, where filecontents is a string
                                    containing the bytes of the attachment
           :param list email_cc: optional list of string values for CC header (to be joined with commas)
           :param list email_bcc: optional list of string values for BCC header (to be joined with commas)
           :param dict headers: optional map of headers to set on the outgoing mail (may override the
                                other headers, including Subject, Reply-To, Message-Id, etc.)
           :rtype: email.message.Message (usually MIMEMultipart)
           :return: the new RFC2822 email message
        """
        email_from = email_from or tools.config.get('email_from')
        assert email_from, "You must either provide a sender address explicitly or configure "\
                           "a global sender address in the server configuration or with the "\
                           "--email-from startup parameter."

        # Note: we must force all strings to to 8-bit utf-8 when crafting message,
        #       or use encode_header() for headers, which does it automatically.

        headers = headers or {} # need valid dict later

        if not email_cc: email_cc = []
        if not email_bcc: email_bcc = []
        if not body: body = u''

        email_body_utf8 = ustr(body).encode('utf-8')
        email_text_part = MIMEText(email_body_utf8, _subtype=subtype, _charset='utf-8')
        msg = MIMEMultipart()

        if not message_id:
            if object_id:
                message_id = tools.generate_tracking_message_id(object_id)
            else:
                message_id = make_msgid()
        msg['Message-Id'] = encode_header(message_id)
        if references:
            msg['references'] = encode_header(references)
        msg['Subject'] = encode_header(subject)
        msg['From'] = encode_rfc2822_address_header(email_from)
        del msg['Reply-To']
        if reply_to:
            msg['Reply-To'] = encode_rfc2822_address_header(reply_to)
        else:
            msg['Reply-To'] = msg['From']
        msg['To'] = encode_rfc2822_address_header(COMMASPACE.join(email_to))
        if email_cc:
            msg['Cc'] = encode_rfc2822_address_header(COMMASPACE.join(email_cc))
        if email_bcc:
            msg['Bcc'] = encode_rfc2822_address_header(COMMASPACE.join(email_bcc))
        msg['Date'] = formatdate()
        # Custom headers may override normal headers or provide additional ones
        for key, value in headers.iteritems():
            msg[ustr(key).encode('utf-8')] = encode_header(value)

        if subtype == 'html' and not body_alternative and html2text:
            # Always provide alternative text body ourselves if possible.
            text_utf8 = tools.html2text(email_body_utf8.decode('utf-8')).encode('utf-8')
            alternative_part = MIMEMultipart(_subtype="alternative")
            alternative_part.attach(MIMEText(text_utf8, _charset='utf-8', _subtype='plain'))
            alternative_part.attach(email_text_part)
            msg.attach(alternative_part)
        elif body_alternative:
            # Include both alternatives, as specified, within a multipart/alternative part
            alternative_part = MIMEMultipart(_subtype="alternative")
            body_alternative_utf8 = ustr(body_alternative).encode('utf-8')
            alternative_body_part = MIMEText(body_alternative_utf8, _subtype=subtype_alternative, _charset='utf-8')
            alternative_part.attach(alternative_body_part)
            alternative_part.attach(email_text_part)
            msg.attach(alternative_part)
        else:
            msg.attach(email_text_part)

        if attachments:
            for (fname, fcontent) in attachments:
                filename_rfc2047 = encode_header_param(fname)
                part = MIMEBase('application', "octet-stream")

                # The default RFC2231 encoding of Message.add_header() works in Thunderbird but not GMail
                # so we fix it by using RFC2047 encoding for the filename instead.
                part.set_param('name', filename_rfc2047)
                part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047)

                part.set_payload(fcontent)
                Encoders.encode_base64(part)
                msg.attach(part)
        return msg
Exemple #43
0
def sendNewEntryNotifications(con, lang, project, category, id, files) :
    
    cursor = con.cursor()
    
    # list of recipients
    query = """
    SELECT mail
    FROM Client
    WHERE
        subscription = True
        AND allowed = True
        AND project = %s
    """
    cursor.execute(query, (projectID(con, project), ))
    recipients = []
    for row in cursor.fetchall() :
        recipients.append(row[0])
    
    # content of the message
    query = """
    SELECT
        Entry.relativeID,
        Entry.name,
        Entry.description,
        Entry.status,
        Entry.severity,
        Client.login,
        Client.mail,
        extract( day FROM Entry.creationDate),
        extract( month FROM Entry.creationDate),
        extract( year FROM Entry.creationDate)
    FROM Entry
    INNER JOIN Client
    ON Entry.creator = Client.id
    WHERE Entry.id = %s"""
    cursor.execute(query, (id, ))
    row = cursor.fetchone()
    relativeID = int(row[0])
    title = row[1]
    description = unFormatText(row[2])
    status = int(row[3])
    severity = int(row[4])
    creator = row[5]
    creatorMail = row[6]
    day = row[7]
    month = row[8]
    year = row[9]
    
    # creating Message-ID for this entry, and therefore the entry-point for the thread
    messageID = make_msgid()
    query = """
    UPDATE Entry SET lastMessageID = %s WHERE id = %s"""
    cursor.execute(query, (messageID,id))
    con.commit()
    
    mytemplate = Template(filename='templates/'+lang+'/mails/newEntry.mail', output_encoding='utf-8', default_filters=['decode.utf8'], input_encoding='utf-8')
    text = mytemplate.render(
        creator = creator,
        title = title,
        description = description,
        files = files,
        status = status,
        severity = severity
    )
    category = category[0].upper()+category[1:].lower()
    
    h = Header()
    h.append(category, 'utf-8')
    h.append(u'#'+str(relativeID)+u':', 'utf-8')
    h.append(title, 'utf-8')
    
    mail = {
        'From' : creator + ' <' + creatorMail + '>',
        'To' : recipients,
        'Subject' : h,
        'Reply-To' : project + '@projects.naphtaline.net',
        'Message-ID' : messageID,
        'In-Reply-To' : '',
        'text' : text,
        'files' : files,
    }
    
    send_mail(mail)
Exemple #44
0
# Processing

tobox = ImapMailbox((toserver, toboxname))
fromboxname = sys.argv[1]
frombox = mailbox.mbox(fromboxname)
frombox.lock()
tobox.lock()

i = 1
print "Processing mbox file %s with %s messages" % (fromboxname, len(frombox))
for message in frombox:
    print "%s" % i
    if message['Message-Id'] is None:
        print "   WARNING: message has no message-id (mesage ID will be added)"
        message.add_header("Message-Id", make_msgid('katamon.mbox2imap'))
    if True:
        try:
            tobox.add(message)
        except ImapNotOkError:
            print "   ERROR: Transaction failed for message %s" % i
            toserver.reconnect()
            tobox = ImapMailbox((toserver, toboxname))
            time.sleep(5)
        time.sleep(1)
        number_in_tobox = len(tobox.get_all_uids())
        #time.sleep(1)
        print "    Added Message, %s in mailbox" % number_in_tobox
    i = i + 1

frombox.close()
Exemple #45
0
def sendNewCommentNotifications(con, lang, project, category, id, content, files) :
    
    cursor = con.cursor()
    
    # creating the list of recipients
    query = """
    SELECT mail
    FROM Client
    WHERE
        subscription = True
        AND allowed = True
        AND project = %s
    """
    cursor.execute(query, (projectID(con, project), ))
    recipients = []
    for row in cursor.fetchall() :
        recipients.append(row[0])
    
    # creating the message
    query = """
    SELECT
        Client.login,
        Client.mail,
        Comment.entry,
        extract( day FROM Comment.creationDate),
        extract( month FROM Comment.creationDate),
        extract( year FROM Comment.creationDate),
        Entry.name,
        Entry.relativeID,
        Entry.lastMessageID
    FROM Comment
    INNER JOIN Entry
    ON Comment.entry = Entry.id
    INNER JOIN Client
    ON Comment.author = Client.id
    WHERE Comment.id = %s"""
    cursor.execute(query, (id, ))
    row = cursor.fetchone()
    author = row[0]
    authorMail = row[1]
    idEntry = int(row[2])
    day = int(row[3])
    month = int(row[4])
    year = int(row[5])
    title = row[6]
    relativeID = int(row[7])
    inReplyTo = row[8]
    
    # updating Message-ID
    messageID = make_msgid()
    query = """
    UPDATE Entry SET lastMessageID = %s WHERE id = %s"""
    cursor.execute(query, (messageID,id))
    con.commit()
    
    mytemplate = Template(filename='templates/'+lang+'/mails/newcomment.mail', output_encoding='utf-8', default_filters=['decode.utf8'], input_encoding='utf-8')
    text = mytemplate.render(
        author = author,
        comment = content,
        files = files
    )
    category = category[0].upper()+category[1:].lower()
    
    h = Header()
    h.append(u'Re:', 'utf-8')
    h.append(category, 'utf-8')
    h.append(u'#'+str(relativeID)+u':', 'utf-8')
    h.append(title, 'utf-8')
    
    mail = {
        'From' : author + ' <' + authorMail + '>',
        'To' : recipients,
        'Subject' : h,
        'Reply-To' : project + '@projects.naphtaline.net',
        'Message-ID' : messageID,
        'In-Reply-To' : inReplyTo,
        'text' : text,
        'files' : files,
    }
    
    send_mail(mail)
def notify_action_needed(target, output_dir, report):
    try:
        json_mtime = os.path.getmtime(output_dir + '/REPORT.json')
    except OSError as e:
        # presumably it only has an old-style REPORT; skip it
        logger.debug('Skipping package %s: %s', report.source_package, e)
        return

    try:
        if json_mtime < os.path.getmtime(output_dir + '/action_needed.eml'):
            logger.debug('already sent notification for %s', output_dir)
            return
    except OSError:
        # file is inaccessible, assume re-notification is necessary
        pass

    ROOT = config.get('ROOT')
    MOM_NAME = config.get('MOM_NAME')
    MOM_EMAIL = config.get('MOM_EMAIL')
    MOM_URL = config.get('MOM_URL')

    obs_project = report.obs_project
    if obs_project is None:
        # guess something reasonable
        obs_project = ':'.join((report.left_distro, report.left_suite,
                                report.left_component))

    rel_output_dir = output_dir
    if rel_output_dir.startswith(ROOT):
        rel_output_dir = rel_output_dir[len(ROOT):]
    rel_output_dir = rel_output_dir.strip('/')

    # Some typical example subject lines:
    # [CONFLICTS] dderivative:alpha:main/curl
    # [FAILED] dderivative:alpha:main/coreutils
    # [MERGED] dderivative:alpha:main/robotfindskitten (if not committable)
    # [NO_BASE] dderivative:alpha:main/hello-debhelper
    # [SYNC_THEIRS] dderivative:alpha:main/hello       (if not committable)
    subject = '[%s] %s/%s' % (report.result, obs_project,
                              report.source_package)
    logger.info('%s', subject)

    message = MIMEMultipart()
    message.add_header('From', '%s <%s>' % (MOM_NAME, MOM_EMAIL))
    message.add_header('To', '%s <%s>' % (MOM_NAME, MOM_EMAIL))
    message.add_header('Date', formatdate())
    message.add_header('Message-ID', make_msgid())
    message.add_header('X-Your-Mom', '%s %s' % (MOM_URL,
                                                report.source_package))
    message.add_header('Subject', subject)

    if report.result == MergeResult.CONFLICTS:
        text = ("""\
This package could not be merged: an automated 3-way merge detected conflicts.
Please carry out a manual merge and commit the result to OBS.
""")
    elif report.result == MergeResult.FAILED:
        text = ("""\
This package could not be merged for some reason. Please carry out a
manual merge and commit the result to OBS.
""")
    elif report.result == MergeResult.MERGED:
        text = ("""\
This package was merged automatically and it seems to have worked.
Please check that the result makes sense.
""")
    elif report.result == MergeResult.NO_BASE:
        text = ("""\
None of the packages' common ancestors could be found in the package pool.
This package cannot be merged until you import one.
""")
    elif report.result == MergeResult.SYNC_THEIRS:
        text = ("""\
The version in the source distribution supersedes our version.
Please check that it's OK to update to the newer version.
""")

    if report.bases_not_found:
        if report.result == MergeResult.NO_BASE:
            text = (text + """\
The most recent common ancestor was:""")
        else:
            text = (text + """
The packages' most recent common ancestor could not be found. This merge
was based on an older common ancestor, but you might get a better-quality
automatic merge if you import this version into the package pool:""")

        text += ("""
    %(base_not_found)s
If that version was in Debian or Ubuntu, you might be able to get it from:
    http://snapshot.debian.org/package/%(source_package)s/
    https://launchpad.net/ubuntu/+source/%(source_package)s
See the "bases_not_found" list in the attached JSON report for some older
versions that might also work.

Download the source package with dget(1) or similar, and put it in:
    %(right_pool_dir)s
before the next merge-o-matic run.
""" % {
            'right_pool_dir': report.right_pool_dir,
            'base_not_found': report.bases_not_found[0],
            'source_package': report.source_package,
        })

    text = (text + """
Our version in %s: %s/%s
Newest common ancestor: %s
Their version in %s:%s:%s: %s
""" % (obs_project,
        report.source_package,
        report.left_version,
        report.base_version,
        report.right_distro,
        report.right_suite,
        report.right_component,
        report.right_version))

    if report.obs_request_url is not None:
        text = (text + """
OBS submit request for the proposed version:
    %s
""" % report.obs_request_url)
    elif report.committed:
        text = (text + """
This package was successfully committed to %s/%s.
""" % (report.committed_to, report.obs_package))
    elif report.commit_detail:
        text = (text + """
A commit to OBS was attempted, but it appears to have failed:
    %s
The merge-o-matic log file might have more details.
""" % report.commit_detail)
    else:
        text = (text + """
This package was not committed to OBS.
""")

    if report.merged_patch is not None:
        text = (text + """
You can view the diff from the upstream version to the proposed version
here:
    %s/%s/%s
""" % (MOM_URL, rel_output_dir, report.merged_patch))

    if report.proposed_patch is not None:
        text = (text + """
You can view the diff from our current version to the proposed version
here:
    %s/%s/%s
""" % (MOM_URL, rel_output_dir, report.proposed_patch))

    if report.right_changelog is not None:
        text = (text + """
The upstream version's changelog is attached.
""")

    dsc = None

    for x in report.merged_files:
        if x.endswith('.dsc'):
            dsc = x

    if dsc is not None:
        text = (text + """
Download the proposed source package for testing here:
    %s/%s/%s
""" % (MOM_URL, rel_output_dir, dsc))

    if report.merge_failure_tarball is not None:
        text = (text + """
You can download a tarball containing the failed merge here:
    %s/%s/%s
""" % (MOM_URL, rel_output_dir, report.merge_failure_tarball))

    text = (text + """
A detailed merge report in JSON format is attached.
More information at:
    %(MOM_URL)s/%(rel_output_dir)s/REPORT.html

Regards,
    the Merge-o-Matic instance at <%(MOM_URL)s>
""" % {
        'MOM_URL': MOM_URL,
        'rel_output_dir': rel_output_dir,
    })

    message.attach(MIMEText(text))

    if report.right_changelog:
        cl_part = MIMEText(
                open(output_dir + '/' + report.right_changelog).read())
        cl_part.add_header('Content-Disposition', 'inline',
                           filename=report.right_changelog)
        message.attach(cl_part)

    json_part = MIMEText(open(output_dir + '/REPORT.json').read())
    json_part.add_header('Content-Disposition', 'inline',
                         filename='%s_REPORT.json' % report.source_package)
    message.attach(json_part)

    if 'MOM_TEST' in os.environ:
        return

    with open(output_dir + '/action_needed.eml.tmp', 'w') as email:
        email.write(message.as_string())

    all_ok = True

    smtp = SMTP('localhost')
    for addr in config.get('RECIPIENTS', default=[]):
        message.replace_header('To', addr)
        try:
            smtp.sendmail(MOM_EMAIL, addr, message.as_string())
        except Exception:
            logger.exception('sending to %s failed:', addr)
            all_ok = False
            smtp = SMTP('localhost')

    # If all emails succeeded,
    if all_ok:
        os.rename(output_dir + '/action_needed.eml.tmp',
                  output_dir + '/action_needed.eml')
Exemple #47
0
    def run(self):
        """ Main entry point """

        # Read command line
        usage = "%prog [options] <url> <address> [<address2>] [<address...>]"
        parser = OptionParser(usage=usage,
                              version=self.NAME + ' ' + self.VERSION)
        parser.add_option("--http-user",
                          dest="http_user",
                          help="Username for HTTP POST authentication")
        parser.add_option("--http-pass",
                          dest="http_pass",
                          help="Password for HTTP POST authentication")
        parser.add_option("-s",
                          "--smtp",
                          dest="smtp",
                          help="SMTP server address. Default: localhost",
                          default='localhost')
        parser.add_option("--smtp-user",
                          dest="smtp_user",
                          help="Username for SMTP authentication")
        parser.add_option("--smtp-pass",
                          dest="smtp_pass",
                          help="Password for SMTP authentication")
        parser.add_option("-c",
                          "--cc",
                          dest="cc",
                          help="Carbon Copy recipient")
        parser.add_option("-f",
                          "--from",
                          dest="sender",
                          help="eMail sender. Default: emailer@localhost",
                          default="emailer@localhost")
        parser.add_option(
            "-j",
            "--subject",
            dest="subject",
            help="eMail Subject. Default: MailWWW Autogenerated Mail",
            default="MailWWW Autogenerated Mail")
        parser.add_option("-n",
                          "--no-css",
                          dest="nocss",
                          help="Disable embedding of linked Style Sheets",
                          default=False,
                          action="store_true")
        parser.add_option(
            "-m",
            "--multiple",
            dest="multiple",
            help=
            "Send multiple emails: one for each recipient (Cc field is ignored)",
            default=False,
            action="store_true")
        parser.add_option("-v",
                          "--verbose",
                          dest="verbose",
                          help="Show progress information",
                          default=False,
                          action="store_true")

        (options, args) = parser.parse_args()

        # Parse mandatory arguments
        if len(args) < 2:
            parser.error("unvalid number of arguments")
        dest = []
        i = 0
        for a in args:
            if i == 0:
                url = a
            else:
                dest.append(a)
            i += 1

        # Parse optional arguments
        http_user = options.http_user
        http_pass = options.http_pass
        cc = []
        if options.cc:
            cc.append(options.cc)
        host = options.smtp
        port = 25
        user = options.smtp_user
        pwd = options.smtp_pass
        sender = options.sender
        subject = options.subject
        nocss = options.nocss
        multiple = options.multiple
        verbose = options.verbose

        logging.basicConfig(level=logging.DEBUG if verbose else logging.INFO)

        # Opens URL
        logging.info('Fetching url %s', url)
        data = None
        if http_user or http_pass:
            # Use POST authentication
            data = urllib.urlencode({
                'username': http_user,
                'password': http_pass,
                'login': True
            })
        f = urllib.urlopen(url, data)
        html = f.read()
        # Search for meta content-type tag, use this encoding when found
        encre = re.compile(
            r'<meta\s+http-equiv=(?:"|\')Content-Type(?:"|\')\s+content=(?:"|\')([^\'"]*)(?:"|\')\s*/>',
            re.I | re.M)
        match = encre.search(html)
        if match:
            encoding = self.__parseEncoding(match.group(1))
            try:
                html = unicode(html, encoding, errors='replace')
            except LookupError as e:
                encoding = self.__parseEncoding(f.headers['content-type'])
                html = unicode(html, encoding, errors='replace')
        else:
            encoding = self.__parseEncoding(f.headers['content-type'])
            html = unicode(html, encoding, errors='replace')
        logging.info('Detected charset: %s', encoding)
        f.close()

        # Retrieve linked style sheets
        if not nocss:
            logging.info('Fetching Style Sheets...')
            parser = CSSLister(url)
            parser.feed(html)
            parser.close()
            for search, replace in parser.get_replacements():
                html = html.replace(search, replace, 1)

        # Prepare mail
        msg = MIMEMultipart()
        msg['Date'] = formatdate(localtime=True)
        msg['Message-ID'] = make_msgid('emailer')
        msg['Subject'] = subject
        msg['From'] = sender

        if cc and not multiple:
            msg['Cc'] = ', '.join(cc)
        msg.preamble = 'This is a milti-part message in MIME format.'

        txt = MIMEText(html.encode('utf-8'), 'html', 'utf-8')
        msg.attach(txt)

        if not multiple:
            msg['To'] = ', '.join(dest)

        # Sends message
        smtp = smtplib.SMTP()
        smtp.connect(host, port)
        if user:
            smtp.login(user, pwd)
        if multiple:
            for d in dest:
                del msg['To']
                msg['To'] = d
                logging.info('Sending mail to: %s', d)
                smtp.sendmail(sender, d, msg.as_string())
        else:
            logging.info('Sending mail to: %s, Cc: %s', dest, cc)
            smtp.sendmail(sender, dest + cc, msg.as_string())
        smtp.quit()
Exemple #48
0
 def _process_utf8(self, kw):
     # sort out what encoding we're going to use
     encoding = kw.get(
         'encoding',
         self.getProperty('encoding', BaseMailTemplate.default_encoding))
     text = self.__class__.__bases__[1].__call__(self, **kw)
     # ZPT adds newline at the end, but it breaks backward compatibility.
     # So I remove it.
     if text and text[-1] == '\n':
         text = text[:-1]
     if not self.html() and isinstance(text, unicode):
         text = text.encode(encoding, 'replace')
     # now turn the result into a MIMEText object
     msg = BaseMailTemplate.MIMEText(text.replace('\r', ''),
                                     self.content_type.split('/')[1],
                                     encoding)
     # sort out what headers and addresses we're going to use
     headers = {}
     values = {}
     # headers from the headers property
     for header in getattr(self, 'headers', ()):
         name, value = header.split(':', 1)
         headers[name] = value
     # headers from the headers parameter
     headers_param = kw.get('headers', {})
     headers.update(headers_param)
     # values and some specific headers
     for key, header in (('mfrom', 'From'), ('mto', 'To'), ('mcc', 'Cc'),
                         ('mbcc', 'Bcc'), ('subject', 'Subject')):
         value = kw.get(
             key,
             headers_param.get(header,
                               getattr(self, key, headers.get(header))))
         if value is not None:
             values[key] = value
             # turn some sequences in coma-seperated strings
             if isinstance(value, (tuple, list)):
                 value = ', '.join(value)
             # make sure we have no unicode headers
             if isinstance(value, unicode):
                 value = value.encode(encoding)
             if key == 'subject':
                 value = make_header([(value, 'utf-8')]).encode()
             headers[header] = value
     # check required values have been supplied
     errors = []
     for param in ('mfrom', 'mto', 'subject'):
         if not values.get(param):
             errors.append(param)
     if errors:
         raise TypeError(
             'The following parameters were required by not specified: ' +
             (', '.join(errors)))
     # add date header
     headers['Date'] = BaseMailTemplate.DateTime().rfc822()
     # add message-id header
     headers['Message-ID'] = make_msgid()
     # turn headers into an ordered list for predictable header order
     keys = headers.keys()
     keys.sort()
     return msg, values, [(key, headers[key]) for key in keys]
def hold(mlist, msg, msgdata, annotation):
    """Hold the message in both Mailman and Launchpad.

    `annotation` is an arbitrary string required by the API.
    """
    # Hold the message in Mailman and Launchpad so that it's easier to
    # resubmit it after approval via the LP u/i.  If the team administrator
    # ends up rejecting the message, it will also be easy to discard it on the
    # Mailman side.  But this way, we don't have to reconstitute the message
    # from the librarian if it gets approved.  However, unlike the standard
    # Moderate handler, we don't craft all the notification messages about
    # this hold.  We also need to keep track of the message-id (which better
    # be unique) because that's how we communicate about the message's status.
    request_id = mlist.HoldMessage(msg, annotation, msgdata)
    assert mlist.Locked(), (
        'Mailing list should be locked: %s' % mlist.internal_name())
    # This is a hack because by default Mailman cannot look up held messages
    # by message-id.  This works because Mailman's persistency layer simply
    # pickles the MailList object, mostly without regard to a known schema.
    #
    # Mapping: message-id -> request-id
    holds = getattr(mlist, 'held_message_ids', None)
    if holds is None:
        holds = mlist.held_message_ids = {}
    message_id = msg.get('message-id')
    if message_id is None:
        msg['Message-ID'] = message_id = make_msgid()
    if message_id in holds:
        # No legitimate sender should ever give us a message with a duplicate
        # message id, so treat this as spam.
        syslog('vette',
               'Discarding duplicate held message-id: %s', message_id)
        raise Errors.DiscardMessage
    # Discard messages that claim to be from the list itself because Mailman's
    # internal handlers did not approve the message before it arrived at this
    # step--these messages are forgeries.
    list_address = mlist.getListAddress()
    for sender in msg.get_senders():
        if list_address == sender:
            syslog('vette',
                   'Discarding forged message-id: %s', message_id)
            raise Errors.DiscardMessage
    # Discard messages without text content since there will be nothing to
    # moderate. Most of these messages are spam.
    if is_message_empty(msg):
        syslog('vette',
               'Discarding text-less message-id: %s', message_id)
        raise Errors.DiscardMessage
    holds[message_id] = request_id
    # In addition to Message-ID, the librarian requires a Date header.
    if 'date' not in msg:
        msg['Date'] = formatdate()
    # Store the message in the librarian.
    proxy = XMLRPCRunner.get_mailing_list_api_proxy()
    # This will fail if we can't talk to Launchpad.  That's okay though
    # because Mailman's IncomingRunner will re-queue the message and re-start
    # processing at this handler.
    proxy.holdMessage(mlist.internal_name(),
                      xmlrpclib.Binary(msg.as_string()))
    syslog('vette', 'Holding message for LP approval: %s', message_id)
    # Raise this exception, signaling to the incoming queue runner that it is
    # done processing this message, and should not send it through any further
    # handlers.
    raise Errors.HoldMessage
Exemple #50
0
# Processing

tobox = ImapMailbox((toserver, toboxname))
fromboxname = sys.argv[1]
frombox = mailbox.mbox(fromboxname)
frombox.lock()
tobox.lock()


i = 1
print "Processing mbox file %s with %s messages" % (fromboxname, len(frombox))
for message in frombox:
    print "%s" % i
    if message['Message-Id'] is None:
        print "   WARNING: message has no message-id (mesage ID will be added)"
        message.add_header("Message-Id", make_msgid('katamon.mbox2imap') )
    if True:
        try:
            tobox.add(message)
        except ImapNotOkError:
            print "   ERROR: Transaction failed for message %s" % i
            toserver.reconnect()
            tobox = ImapMailbox((toserver, toboxname))
            time.sleep(5)
        time.sleep(1)
        number_in_tobox = len(tobox.get_all_uids())
        #time.sleep(1)
        print "    Added Message, %s in mailbox" % number_in_tobox
    i = i + 1

frombox.close()
Exemple #51
0
def sendmail(request, to, subject, text, **kw):
    """
    Send a mail to the address(es) in 'to', with the given subject and
    mail body 'text'.
    
    Return a tuple of success or error indicator and message.

    Set a different "From" address with "mail_from=<email>".
    @param request: the request object
    @param to: target email address
    @param subject: subject of email
    @param text: email body text
    @rtype: tuple
    @return: (is_ok, msg)
    """

    _ = request.getText
    # should not happen, but who knows ...
    if not config.mail_smarthost:
        return (
            0,
            _(
                "This wiki is not enabled for mail processing. "
                "Contact the owner of the wiki, who can either enable "
                'email, or remove the "Subscribe" icon.'
            ),
        )
    mail_from = kw.get("mail_from", config.mail_from) or config.mail_from

    # Create a text/plain message
    msg = MIMEText(text, "plain", config.charset)
    msg["From"] = mail_from
    msg["To"] = ", ".join(to)
    msg["Date"] = formatdate()

    try:  # only python >= 2.2.2 has this:
        from email.Header import Header
        from email.Utils import make_msgid

        msg["Message-ID"] = make_msgid()
        msg["Subject"] = Header(subject, config.charset)
    except ImportError:
        # this is not standards compliant, but mostly works
        msg["Subject"] = subject
        # no message-id. if you still have py 2.2.1, you like it old and broken

    try:
        server = smtplib.SMTP(config.mail_smarthost, config.mail_port, config.domain)
        try:
            if config.use_tls:
                server.ehlo()
                server.starttls()
                server.ehlo()
            # server.set_debuglevel(1)
            if config.mail_smarthost_auth:
                user, pwd = config.mail_smarthost_auth
                server.login(user, pwd)
            server.sendmail(mail_from, to, msg.as_string())
        finally:
            try:
                server.quit()
            except AttributeError:
                # in case the connection failed, SMTP has no "sock" attribute
                pass
    except smtplib.SMTPException, e:
        return (0, str(e))
Exemple #52
0
    def build_invitation(
        self,
        email_from='',
        email_to='',
        subject='',
        email_cc=[],
        email_bcc=[],
        reply_to=False,
        attachments=None,
        message_id=None,
        references=None,
        object_id=False,
        headers={},
    ):
        email_from = email_from or tools.config.get('email_from')
        assert email_from, "You must either provide a sender address explicitly or configure "\
                           "a global sender address in the server configuration or with the "\
                           "--email-from startup parameter."
        msg = MIMEMultipart()
        if not headers:
            headers = {}
        if not message_id:
            if object_id:
                message_id = tools.generate_tracking_message_id(object_id)
            else:
                message_id = make_msgid()
        msg['Message-Id'] = encode_header(message_id)
        if references:
            msg['references'] = encode_header(references)
        msg['Subject'] = encode_header(subject)
        msg['From'] = encode_rfc2822_address_header(email_from)
        del msg['Reply-To']
        if reply_to:
            msg['Reply-To'] = encode_rfc2822_address_header(reply_to)
        else:
            msg['Reply-To'] = msg['From']
        msg['To'] = encode_rfc2822_address_header(COMMASPACE.join(email_to))
        if email_cc:
            msg['Cc'] = encode_rfc2822_address_header(
                COMMASPACE.join(email_cc))
        if email_bcc:
            msg['Bcc'] = encode_rfc2822_address_header(
                COMMASPACE.join(email_bcc))
        msg['Date'] = formatdate()
        for key, value in headers.items():
            msg[ustr(key).encode('utf-8')] = encode_header(value)

        text_to_body_added = False
        if attachments:
            #it is assumed for now that only ics file is attached!!!
            for fname, fcontent in attachments:
                if not text_to_body_added and fname == 'invite.ics':
                    # Provide message description in body of message only as text for now; need fixes
                    if 'DESCRIPTION:' in fcontent and 'LOCATION' in fcontent.split(
                            'DESCRIPTION')[1]:
                        meeting_description_text = fcontent.split(
                            'DESCRIPTION:')[1].split('LOCATION')[0]
                    text_converted_to_html = self.plaintext2html(
                        meeting_description_text, tabstop=4)
                    text_utf8 = re.sub(r'\\n', "</p><p>",
                                       text_converted_to_html)
                    alternative_part = MIMEMultipart(_subtype="alternative")
                    alternative_part.attach(
                        MIMEText(text_utf8, _charset='utf-8', _subtype='html'))
                    msg.attach(alternative_part)
                #adding invitation stuff
                part = MIMEBase('text',
                                'calendar',
                                charset='utf-8',
                                method='REQUEST')
                part.set_payload(fcontent)
                msg.attach(part)
        return msg
Exemple #53
0
    def _process(self, kw):
        # sort out what encoding we're going to use
        encoding = kw.get('encoding',
                          self.getProperty('encoding', default_encoding))
        text = self.__class__.__bases__[1].__call__(self, **kw)
        # ZPT adds newline at the end, but it breaks backward compatibility.
        # So I remove it.
        if text.endswith('\n'):
            text = text[:-1]
        if not self.html() and isinstance(text, unicode):
            text = text.encode(encoding, 'replace')
        # now turn the result into a MIMEText object
        msg = MIMEText(text.replace('\r', ''),
                       self.content_type.split('/')[1], encoding)
        # sort out what headers and addresses we're going to use
        headers = {}
        values = {}
        # headers from the headers property
        for header in getattr(self, 'headers', ()):
            name, value = header.split(':', 1)
            headers[name] = value
        # headers from the headers parameter
        headers_param = kw.get('headers', {})
        headers.update(headers_param)
        # values and some specific headers
        for key, header in (('mfrom', 'From'), ('mto', 'To'), ('mcc', 'Cc'),
                            ('mbcc', 'Bcc'), ('subject', 'Subject')):
            value = kw.get(
                key,
                headers_param.get(header,
                                  getattr(self, key, headers.get(header))))
            if value is not None:
                values[key] = value

                if key == 'subject':
                    try:
                        # Try to keep header non encoded
                        value = Header(value)
                    except UnicodeDecodeError:
                        value = Header(value, "UTF-8")

                else:
                    dest_list = []
                    for name, email in getaddresses(
                        (value, ) if isinstance(value, basestring) else value):
                        try:
                            name = Header(name)
                        except UnicodeDecodeError:
                            name = Header(name, "UTF-8")
                        dest_list.append(formataddr((name.encode(), email)))
                    value = ", ".join(dest_list)

                headers[header] = value
        # check required values have been supplied
        errors = []
        for param in ('mfrom', 'mto'):
            if not values.get(param):
                errors.append(param)
        if errors:
            raise TypeError(
                'The following parameters were required by not specified: ' +
                (', '.join(errors)))
        # add date header
        headers['Date'] = DateTime().rfc822()
        # do not let the MTA to generate the Message-ID:
        # we want to have it stored in ERP5, for mail threading
        headers['Message-ID'] = make_msgid()
        # turn headers into an ordered list for predictable header order
        keys = headers.keys()
        keys.sort()
        return msg, values, [(key, headers[key]) for key in keys]