Example #1
0
 def test_parseaddr(self):
     eq = self.assertEqual
     eq(rfc822.parseaddr('<>'), ('', ''))
     eq(rfc822.parseaddr('*****@*****.**'), ('', '*****@*****.**'))
     eq(rfc822.parseaddr('[email protected] (Bea A. Person)'),
        ('Bea A. Person', '*****@*****.**'))
     eq(rfc822.parseaddr('Cynthia Person <*****@*****.**>'),
        ('Cynthia Person', '*****@*****.**'))
Example #2
0
 def add_bcc(self, bcc):
     if isinstance(bcc, str):
         email = rfc822.parseaddr(bcc.replace(",", ""))[1]
         self.bcc.append(email)
     elif sys.version_info < (3, 0) and isinstance(bcc, unicode):
         email = rfc822.parseaddr(bcc.replace(",", ""))[1].encode("utf-8")
         self.bcc.append(email)
     elif hasattr(bcc, "__iter__"):
         for email in bcc:
             self.add_bcc(email)
 def add_cc(self, cc):
     if isinstance(cc, str):
         email = rfc822.parseaddr(cc.replace(',', ''))[1]
         self.cc.append(email)
     elif sys.version_info < (3, 0) and isinstance(cc, unicode):
         email = rfc822.parseaddr(cc.replace(',', ''))[1].encode('utf-8')
         self.cc.append(email)
     elif hasattr(cc, '__iter__'):
         for email in cc:
             self.add_cc(email)
Example #4
0
def write_status_json(component, merges, left_distro, right_distro):
    """Write out the merge status JSON dump."""
    status_file = "%s/merges/%s.json" % (ROOT, component)
    with open(status_file + ".new", "w") as status:
        # No json module available on merges.tanglu.org right now, but it's
        # not that hard to do it ourselves.
        print('[', file=status)
        cur_merge = 0
        for uploaded, priority, package, user, uploader, source, \
                base_version, left_version, right_version in merges:
            print(' {', end=' ', file=status)
            # source_package, short_description, and link are for
            # Harvest (http://daniel.holba.ch/blog/?p=838).
            print('"source_package": "%s",' % package, end=' ', file=status)
            print('"short_description": "merge %s",' % right_version,
                  end=' ', file=status)
            print('"link": "https://merges.tanglu.org/%s/%s/",' %
                  (pathhash(package), package), end=' ', file=status)
            print('"uploaded": "%s",' % uploaded, end=' ', file=status)
            print('"priority": "%s",' % priority, end=' ', file=status)
            if user is not None:
                who = user
                who = who.replace('\\', '\\\\')
                who = who.replace('"', '\\"')
                print('"user": "******",' % who, end=' ', file=status)
                if uploader is not None:
                    (usr_name, usr_mail) = parseaddr(user)
                    (upl_name, upl_mail) = parseaddr(uploader)
                    if len(usr_name) and usr_name != upl_name:
                        u_who = uploader
                        u_who = u_who.replace('\\', '\\\\')
                        u_who = u_who.replace('"', '\\"')
                        print('"uploader": "%s",' % u_who, end=' ', file=status)
            binaries = re.split(', *', source["Binary"].replace('\n', ''))
            print('"binaries": [ %s ],' %
                  ', '.join(['"%s"' % b for b in binaries]),
                  end=' ', file=status)
            print('"base_version": "%s",' % base_version, end=' ', file=status)
            print('"left_version": "%s",' % left_version, end=' ', file=status)
            print('"right_version": "%s"' % right_version,
                  end=' ', file=status)
            cur_merge += 1
            if cur_merge < len(merges):
                print('},', file=status)
            else:
                print('}', file=status)
        print(']', file=status)

    os.rename(status_file + ".new", status_file)
    def migrate(self):
        if self.is_updated(): 
            return 'already migrated'
        
        # set the appropriate list type based on the previous settings
        # this may need to mark the appropriate interface on the mailing
        # list as well
        if self.context.moderated:
            self.context.list_type = PostModeratedListTypeDefinition
        elif self.context.closed:
            self.context.list_type = MembershipModeratedListTypeDefinition
        else:
            self.context.list_type = PublicListTypeDefinition

        # copy over the membership stuff
        annot = IAnnotations(self.context)
        listen_annot = annot.get('listen', {})
        old_subscribers = listen_annot.get('subscribers', [])

        # create the new annotations by using current adapters
        mem_list = IWriteMembershipList(self.context)
        for subscriber in old_subscribers:
            mem_list.subscribe(subscriber)

        # unsubscribe (but leave as allowed senders) those who don't 
        # receive mail
        nomail = listen_annot.get('norecvmail', [])
        for allowed_sender in nomail:
            mem_list.unsubscribe(allowed_sender)

        # copy over the moderation messages
        self.mod_post_pending_list = getAdapter(self.context, IPostPendingList, 'pending_pmod_post')
        for i in self.context.mqueue.objectIds():
            (header, body) = splitMail(self.context.mqueue[i])
            post = {'header':header, 'body':body}
            (user_name, user_email) = parseaddr(header.get('from', ''))
            self.mod_post_pending_list.add(user_email, user_name=user_name, post=post)

        # creates list managers from moderators and list owner
        managers = []
        managers.append(self.context.list_owner)
        for moderator in self.context.moderators:
            managers.append(moderator)
        self.context.managers = tuple(managers)
        convert_manager_emails_to_memberids(self.context)

        # translate archived vocabulary
        if self.context.archived == 'not archived':
            self.context.archived = 2
        elif self.context.archived == 'plain text':
            self.context.archived = 1
        elif self.context.archived == 'with attachments':
            self.context.archived = 0
        else:
            return 'error translating archive option'

        # annotate the list to say the migration completed
        self.migration_annot.append('policy_migration')

        return 'successfully migrated'
Example #6
0
def parse_person(val):
    """Parse a full email address into human-readable name and address."""
    # Some addresses have commas in them, as in: "Adam C. Powell, IV
    # <*****@*****.**>". rfc822.parseaddr seems not to
    # handle this properly, so we munge them here.
    val = val.replace(',', '')
    return rfc822.parseaddr(val)
def getAddressInfo(obj, subscription_manager):
    if subscription_manager is not None:
        from_name, from_addr = parseaddr(obj.from_addr)
        user = lookup_member_id(from_addr, obj)
        if user is not None:
            return user, obj.from_addr
    return None, obj.from_addr
Example #8
0
File: load.py Project: edsu/rage14
def get_message(msg):
    fr = rfc822.parseaddr(msg['from'])
    to = rfc822.AddressList(msg['to']).addresslist
    cc = rfc822.AddressList(msg['cc']).addresslist
    subject = msg['subject']
    date = rfc822.parsedate(msg['date'])
    date = datetime.datetime(*date[:6])
    url = msg['Archived-At']
    if not url: 
        url = msg['X-Archived-At']
    url = url.strip("<>")
    message_id = msg['Message-ID']
    in_reply_to = msg.get('In-Reply-To', None)

    return {
        "from": fr,
        "subject": subject,
        "to": to,
        "cc": cc,
        "url": url,
        "date": date,
        "message_id": message_id,
        "in_reply_to": in_reply_to,
        "raw": msg.as_string()
    }

    return None
Example #9
0
 def add_bcc(self, bcc):
     if isinstance(bcc, str):
         email = rfc822.parseaddr(bcc.replace(',', ''))[1]
         self.bcc.append(email)
     else:
         for email in bcc:
             self.add_bcc(email)
Example #10
0
    def _checkStateMX(self):
        nextMessages = self.queue.getWaiting()
        nextMessages.reverse()

        exchanges = {}
        for msg in nextMessages:
            from_, to = self.queue.getEnvelope(msg)
            name, addr = rfc822.parseaddr(to)
            parts = addr.split('@', 1)
            if len(parts) != 2:
                log.err("Illegal message destination: " + to)
                continue
            domain = parts[1]

            self.queue.setRelaying(msg)
            exchanges.setdefault(domain, []).append(self.queue.getPath(msg))
            if len(exchanges) >= (self.maxConnections - len(self.managed)):
                break

        if self.mxcalc is None:
            self.mxcalc = MXCalculator()

        relays = []
        for (domain, msgs) in exchanges.iteritems():
            manager = _AttemptManager(self)
            factory = self.factory(msgs, manager, *self.fArgs, **self.fKwArgs)
            self.managed[factory] = map(os.path.basename, msgs)
            relayAttemptDeferred = manager.getCompletionDeferred()
            connectSetupDeferred = self.mxcalc.getMX(domain)
            connectSetupDeferred.addCallback(lambda mx: str(mx.name))
            connectSetupDeferred.addCallback(self._cbExchange, self.PORT, factory)
            connectSetupDeferred.addErrback(lambda err: (relayAttemptDeferred.errback(err), err)[1])
            connectSetupDeferred.addErrback(self._ebExchange, factory, domain)
            relays.append(relayAttemptDeferred)
        return DeferredList(relays)
Example #11
0
 def _checkStateMX(self):
     nextMessages = self.queue.getWaiting()
     nextMessages.reverse()
     
     exchanges = {}
     for msg in nextMessages:
         from_, to = self.queue.getEnvelope(msg)
         name, addr = rfc822.parseaddr(to)
         parts = addr.split('@', 1)
         if len(parts) != 2:
             log.err("Illegal message destination: " + to)
             continue
         domain = parts[1]
         
         self.queue.setRelaying(msg)
         exchanges.setdefault(domain, []).append(self.queue.getPath(msg))
         if len(exchanges) >= (self.maxConnections - len(self.managed)):
             break
     
     if self.mxcalc is None:
         self.mxcalc = MXCalculator()
     
     for (domain, msgs) in exchanges.iteritems():
         factory = self.factory(msgs, self, *self.fArgs, **self.fKwArgs)
         self.managed[factory] = map(os.path.basename, msgs)
         self.mxcalc.getMX(domain
         ).addCallback(lambda mx: str(mx.name),
         ).addCallback(self._cbExchange, self.PORT, factory
         ).addErrback(self._ebExchange, factory, domain
         )
Example #12
0
        def recoverDelayed(self, addr, smtp):
            try:
                    filename = self.config.homedir + '/.animail/animailDelayed/' + addr
                    fp = open(filename,'r+')
                    mbox = mailbox.UnixMailbox(fp)
                    mail = mbox.next()
                    mailcount = 0
                    while mail != None:
                                header = ''.join(mail.headers)
                                body = ''
                                line = 'Ugh, This is a BUG in ANIMAIL'
                                while (line[:5] != 'From ' ) and (line != ''):
                                    line = fp.readline()
                                    body += line

                                (foo,FROM) = rfc822.parseaddr(mail['from'])
                                if self.__class__.__name__ == "Pop3Server":
                                    body = header + body

                                self.deliver_smtp(header,body,FROM,smtp)
                                mailcount += 1
                                mail = mbox.next()
                    aprint(_("%d mails recovered from %s") % (mailcount, addr), general.VIOLET)
                    fp.close()
            except:
                    print _("Error trying to delete the delayed mbox of the address %s") % addr
                    print _("The mailbox won't be deleted, if you want to read those messages")
                    print _("open it manually (.animail/animailDelayed/%s)") % addr
                    print _("The error was: ")
                    import traceback
                    traceback.print_exc(file=sys.stderr)
                    return
            os.unlink(filename)
 def mail_from_name(self, do_encode=True):
     addr = self.context.from_addr
     name = parseaddr(addr)[0] or addr
     if do_encode:
         return encode(name, self.getMailingList())
     else:
         return name
Example #14
0
 def parse_and_add(self, to):
     super(Mail, self).add_to(to)
     name, email = rfc822.parseaddr(to.replace(',', ''))
     if email:
         self.to.append(email)
     if name:
         self.add_to_name(name)
Example #15
0
    def check_lists(self, config):
        """ Check if the user is authorized to use the handler """

	# Use email part of sender
        (name, sender) = rfc822.parseaddr(self.sender)
	self.log.debug("[check_lists]: sender = %s" % self.sender)
	self.log.debug("[check_lists]: sender(email) = %s" % sender)

        # First check black list
        if config.has_option(self.section, "BLACK_LIST"):
	    self.log.debug("[check_lists]: BLACK_LIST exists")
            BL = config.get(self.section, "BLACK_LIST")
	    self.log.debug("[check_lists]: BLACK_LIST=%s" % BL)
            if sender in BL:
                return False

        # Black list is not bloquing, check white list
        if config.has_option(self.section, "WHITE_LIST"):
	    self.log.debug("[check_lists]: WHITE_LIST exists")
            WL = config.get(self.section, "WHITE_LIST")
	    self.log.debug("[check_lists]: WHITE_LIST=%s" % WL)
            return sender in WL
        
        else:
            # If no white list is provided, mbot usage is accepted
            return True
Example #16
0
 def visit_field(self, node):
     if isinstance(node.parent, nodes.docinfo):
         name = node[0].astext().lower().replace(" ","")
         if name == "moduleauthor":
             (ename, email) = rfc822.parseaddr(node[1].astext())
             self.docinfo["moduleauthor"] = ename
             self.docinfo["moduleauthoremail"] = email
         elif name in ("author", "sectionauthor") :
             (ename, email) = rfc822.parseaddr(node[1].astext())
             self.docinfo["sectionauthor"] = ename
             self.docinfo["sectionauthoremail"] = email
         else:
             if name == "module":
                 self.set_label_prefix(node[1].astext())
             self.docinfo[name] = node[1].astext()
         raise nodes.SkipNode
Example #17
0
 def _from(self, fromfield):
     (name, email) = rfc822.parseaddr(fromfield)
     if name == None and email == None:
         print 'Warning!  Could not parse ' + fromfield + '.  Skipping.'
         return {}
     [(text, charset)] = header.decode_header(name)
     name = unicode(text, charset or 'ascii')
     return {'name': name, 'email': email.lower()}
Example #18
0
def create_form_from_mail(config, mail, tmpfn):
    subject = mail.get("Subject", "[no subject]")
    sender = mail.get("From", "Unknown <*****@*****.**>")
    
    xml = None
    body = ""

    if mail.is_multipart():
        html = None
        for part in mail.walk():
            if part.get_content_maintype() == "multipart":
                continue
            elif part.get_content_type() == "d-rats/form_xml":
                xml = str(part.get_payload())
                break # A form payload trumps all
            elif part.get_content_type() == "text/plain":
                body += part.get_payload(decode=True)
            elif part.get_content_type() == "text/html":
                html = part.get_payload(decode=True)
        if not body:
            body = html
    else:
        body = mail.get_payload(decode=True)

    if not body and not xml:
        raise Exception("Unable to find a usable part")

    messageid = mail.get("Message-ID", time.strftime("%m%d%Y%H%M%S"))
    if not msgrouting.msg_lock(tmpfn):
        print "AIEE: Unable to lock incoming email message file!"

    if xml:
        f = file(tmpfn, "w")
        f.write(xml)
        f.close()
        form = formgui.FormFile(tmpfn)
        recip = form.get_recipient_string()
        if "%" in recip:
            recip, addr = recip.split("%", 1)
            recip = recip.upper()
    else:
        print "Email from %s: %s" % (sender, subject)

        recip, addr = rfc822.parseaddr(mail.get("To", "UNKNOWN"))

        efn = os.path.join(config.form_source_dir(), "email.xml")
        form = formgui.FormFile(efn)
        form.set_field_value("_auto_sender", sender)
        form.set_field_value("recipient", recip)
        form.set_field_value("subject", "EMAIL: %s" % subject)
        form.set_field_value("message", utils.filter_to_ascii(body))
        form.set_path_src(sender.strip())
        form.set_path_dst(recip.strip())
        form.set_path_mid(messageid)

    form.save_to(tmpfn)

    return form
Example #19
0
 def to_addresses(self):
     addresses = []
     for address in self.to_header.split(','):
         addresses.append(
                 rfc822.parseaddr(
                         address
                     )[1]
             )
     return addresses
Example #20
0
File: simple.py Project: apg/canoe
def sanitize_addrs(addrs):
    naddrs = []
    for addr in addrs:
        _, a = rfc822.parseaddr(addr.strip())
        if a and len(a) > 0:
            naddrs.append(a)
        else:
            print "ERROR: ", _, a

    return quote_addrs(naddrs)
Example #21
0
 def __getitem__(self, key):
     lkey = key.lower()
     if not self.message.has_key(key):
         raise AttributeError, "%s has no such key %s" % (repr(self), key)
     if lkey in ['to', 'bcc', 'cc']:
         adrs = self.get_addresslist(lkey)
         return adrs
     elif lkey in ['from', 'envelope-to']:
         return parseaddr(self.message[lkey])
     return self.message[key]
Example #22
0
 def add_to(self, to):
     if isinstance(to, str):
         name, email = rfc822.parseaddr(to.replace(',', ''))
         if email:
             self.to.append(email)
         if name:
             self.add_to_name(name)
     else:
         for email in to:
             self.add_to(email)
Example #23
0
def import_emails(messages):
  for message in messages:

    subject = message.subject
    if 'Fwd: ' in subject:
      subject = subject.strip('Fwd: ')
    subject = subject.title()

    m = Email(
          html=message.html.as_string(), 
          text=message.body.as_string(), 
          author_address=message.fr, 
          author_name=rfc822.parseaddr(message.fr)[0],
          # -1 gets last element in array
          domain=rfc822.parseaddr(message.fr)[-1].split('@')[-1],
          subject=subject
        )
    print 'Adding message:', subject
    db_session.add(m)
  db_session.commit()
Example #24
0
 def PVT_infer_broken_attrs(self):
     """PRIVATE: Infer needed attributes from email header"""
     self.attr["package"] = re.search('package="([^"]*)"', self.subject).group(1)
     self.attr["profile"] = re.search('profile="([^"]*)"', self.subject).group(1)
     self.attr["session"] = re.search('session="([^"]*)"', self.subject).group(1)
     self.attr["date_text"] = self.date
     self.attr["date"] = "%04d-%02d-%02d" % self.date_tuple[0:3]
     self.attr["time"] = "%d:%d:%d" % self.date_tuple[3:6]
     email = rfc822.parseaddr(self.fromwhom)[1]
     self.attr["whoami"] = re.search("^([^@]*)@", email).group(1)
     self.attr["hostname"] = re.search("@(.*)", email).group(1)
     self.attr["result"] = "BROKEN"
Example #25
0
def address_part(email):
    """
    Returns the email part of the address
    
    >>> address_part('*****@*****.**')
    '*****@*****.**'
    
    >>> address_part('Tester <*****@*****.**>')
    '*****@*****.**'

    """
    return rfc822.parseaddr(email)[1]
 def __call__(self, message, mailboxer, REQUEST):
     mailString = message.as_string()
     (header, body) = mailboxer.splitMail(mailString)
     if header.get('x-mailer') == mailboxer.getValueFor('xmailer'):
         logmessage = 'Mail already processed'
         LOG('MailBoxer', PROBLEM, logmessage)
         #return logmessage
         raise ValidatorException(logmessage)
     # Check for empty return-path => automatic mail
     if header.get('return-path', '') == '<>':
         mailboxer.bounceMail(REQUEST)
         logmessage = 'Automated response detected from %s'
         LOG('MailBoxer', PROBLEM, logmessage % (header.get('from', '<>')))
         #return (message)
         raise ValidatorException(logmessage)
     # Check for hosed denial-of-service-vacation mailers
     # or other infinite mail-loops...
     sender = mailboxer.mime_decode_header(header.get('from', 'No Sender'))
     (name, email) = rfc822.parseaddr(sender)
     email = email.lower()
     disabled = list(mailboxer.getValueFor('disabled'))
     if email in disabled:
         logmessage = '%s is disabled.' % sender
         LOG('MailBoxer', PROBLEM, logmessage)
         #return logmessage
         raise ValidatorException(logmessage)
     senderlimit = mailboxer.getValueFor('senderlimit')
     senderinterval = mailboxer.getValueFor('senderinterval')
     if senderlimit and senderinterval:
         sendercache = mailboxer.sendercache
         ntime = int(DateTime())
         if sendercache.has_key(email):
             sendercache[email].insert(0, ntime)
         else:
             sendercache[email] = [ntime]
         etime = ntime-senderinterval
         count = 0
         for atime in sendercache[email]:
             if atime > etime:
                 count += 1
             else:
                 break
         # prune our cache back to the time intervall
         sendercache[email] = sendercache[email][:count]
         mailboxer.sendercache = sendercache
         if count > senderlimit:
             if email not in disabled:
                 mailboxer.setValueFor('disabled', disabled + [email])
             logmessage = ('Sender %s has sent %s mails in %s seconds' %
                                           (sender, count, senderinterval))
             LOG('MailBoxer', PROBLEM, logmessage)
             #return logmessage
             raise ValidatorException(logmessage)
Example #27
0
    def _build_sg_mail(self, email):
        mail = sendgrid.Mail()
        
        # use smtpapi if recipient list provided, otherwise use standard to field
        if isinstance(email.to, list):
            mail.smtpapi.set_tos(email.to)
        else:
            mail.add_to(email.to)

        mail.add_cc(email.cc)
        mail.add_bcc(email.bcc)
        mail.set_text(email.body)
        mail.set_subject(email.subject)
        mail.set_from(email.from_email)

        if isinstance(email, EmailMultiAlternatives):
            for alt in email.alternatives:
                if alt[1] == "text/html":
                    mail.set_html(alt[0])

        for attachment in email.attachments:
            if isinstance(attachment, MIMEBase):
                mail.add_attachment_stream(
                    attachment.get_filename(),
                    attachment.get_payload())
            elif isinstance(attachment, tuple):
                mail.add_attachment_stream(attachment[0], attachment[1])

        if email.extra_headers:
            if "Reply-To" in email.extra_headers:
                reply_to = rfc822.parseaddr(email.extra_headers["Reply-To"])[1]
                mail.set_replyto(reply_to)

            if "Subs" in email.extra_headers:
                mail.set_substitutions(email.extra_headers["Subs"])

            if "Sections" in email.extra_headers:
                mail.set_sections(email.extra_headers["Sections"])

            if "Categories" in email.extra_headers:
                mail.set_categories(email.extra_headers["Categories"])

            if "Unique-Args" in email.extra_headers:
                mail.set_unique_args(email.extra_headers["Unique-Args"])

            if "Filters" in email.extra_headers:
                mail.smtpapi.data['filters'] = email.extra_headers["Filters"]

            for attachment in email.attachments:
                mail.add_attachment_stream(attachment[0], attachment[1])

        return mail
Example #28
0
def build_sengrid_mail(email, check=True, fail=True):
    if check and not is_handled(email, fail=fail):
        return

    mail = sendgrid.Mail()
    mail.add_to(email.to)
    mail.add_cc(email.cc)
    mail.add_bcc(email.bcc)
    mail.set_subject(email.subject)
    mail.set_from(email.from_email)

    text, html = ('', email.body) if email.content_subtype == 'html' else (email.body, '')
    if not html and hasattr(email, 'alternatives'):
        try:
            html = next(c for c, t in email.alternatives if t == 'text/html')
        except StopIteration:
            pass
    mail.set_text(text)
    mail.set_html(html)

    for attachment in email.attachments:
        if isinstance(attachment, MIMEBase):
            mail.add_attachment_stream(
                attachment.get_filename(),
                attachment.get_payload())
        elif isinstance(attachment, tuple):
            mail.add_attachment_stream(attachment[0], attachment[1])

    if email.extra_headers:
        if 'Reply-To' in email.extra_headers:
            reply_to = rfc822.parseaddr(email.extra_headers['Reply-To'])[1]
            mail.set_replyto(reply_to)

        if 'Subs' in email.extra_headers:
            mail.set_substitutions(email.extra_headers['Subs'])

        if 'Sections' in email.extra_headers:
            mail.set_sections(email.extra_headers['Sections'])

        if 'Categories' in email.extra_headers:
            mail.set_categories(email.extra_headers['Categories'])

        if 'Unique-Args' in email.extra_headers:
            mail.set_unique_args(email.extra_headers['Unique-Args'])

        if 'Filters' in email.extra_headers:
            mail.smtpapi.data['filters'] = email.extra_headers['Filters']

        for attachment in email.attachments:
            mail.add_attachment_stream(attachment[0], attachment[1])

    return mail
Example #29
0
def generateConfirmation(toaddr): 
    config = AnimailMain.Application.config
    (foo,fromaddr) = rfc822.parseaddr(config.replyaddress)
    serv = smtplib.SMTP('localhost')
    heads = ("Subject: %s [%s]\r\n\r\n" % (config.confirmsubject,fromaddr))
    if config.filewithreply == '':
        tmpmsg = general.ConfirmDefaultStr
    else:
        tmpmsg = ''.join(open(config.filewithreply).readlines())
    msg = heads + tmpmsg
    serv.sendmail(fromaddr, toaddr, msg)
    aprint(_("Confirmation succesfully send to %s") % toaddr, general.VIOLET)
    serv.quit()
Example #30
0
 def format_message(self, message):
     """returned a dictionary with some fields needed for the template"""
     from_addr = message['from']
     quoted_subject = urllib.quote(message['subject'])
     name, email = parseaddr(from_addr)
     # if there is no name, use the email address in its place
     name = name or email
     archive_url = message.get('X-listen-message-url',
                               self.context.absolute_url())
     return dict(from_name=name,
                 from_email=email,
                 quoted_subject=quoted_subject,
                 archive_url=archive_url,
                 )
    def parse_email(self, email_info):
        name, email = rfc822.parseaddr(email_info)

        # more than likely a string was passed here instead of an email address
        if "@" not in email:
            name = email
            email = None

        if not name:
            name = None

        if not email:
            email = None

        self.name = name
        self.email = email
        return name, email
Example #32
0
    def _build_sg_mail(self, email):
        mail = sendgrid.Mail()
        mail.add_to(email.to)
        mail.add_cc(email.cc)
        mail.add_bcc(email.bcc)
        mail.set_text(email.body)
        mail.set_subject(email.subject)
        mail.set_from(email.from_email)

        if isinstance(email, EmailMultiAlternatives):
            for alt in email.alternatives:
                if alt[1] == "text/html":
                    mail.set_html(alt[0])

        for attachment in email.attachments:
            if isinstance(attachment, MIMEBase):
                mail.add_attachment_stream(attachment.get_filename(),
                                           attachment.get_payload())
            elif isinstance(attachment, tuple):
                mail.add_attachment_stream(attachment[0], attachment[1])

        if email.extra_headers:
            if "Reply-To" in email.extra_headers:
                reply_to = rfc822.parseaddr(email.extra_headers["Reply-To"])[1]
                mail.set_replyto(reply_to)

            if "Subs" in email.extra_headers:
                mail.set_substitutions(email.extra_headers["Subs"])

            if "Sections" in email.extra_headers:
                mail.set_sections(email.extra_headers["Sections"])

            if "Categories" in email.extra_headers:
                mail.set_categories(email.extra_headers["Categories"])

            if "Unique-Args" in email.extra_headers:
                mail.set_unique_args(email.extra_headers["Unique-Args"])

            if "Filters" in email.extra_headers:
                mail.smtpapi.data['filters'] = email.extra_headers["Filters"]

            for attachment in email.attachments:
                mail.add_attachment_stream(attachment[0], attachment[1])

        return mail
Example #33
0
 def email_valid(email):
     # rfc822 is pretty forgiving, but we want to be strict. [rp]
     is_valid = False
     if email:
         real_name, email_addy = rfc822.parseaddr(email)
         if email == email_addy:
             is_valid = True
         else:
             # 2012.11.12: [lb] is not sure this ever happens. Parseaddr just
             # splits a To: or a From: into the friendly name and the email
             # address, e.g., "Some Person <*****@*****.**>".
             # See BUG 2763: Bad email addys.
             log.warning(
                 'Since when does rfc822.parseaddr fail? "%s" != "%s"' % (
                     email,
                     email_addy,
                 ))
     return is_valid
Example #34
0
def generatereply(toaddr):
    config = AnimailMain.Application.config
    fromaddr = config.replyaddress
    serv = smtplib.SMTP('localhost')
    (foo, emailaddr) = rfc822.parseaddr(config.replyaddress.strip())
    heads = ("Subject: %s [%s]\r\n\r\n" % (config.replysubject, emailaddr))
    if config.filewithreply == '':
        tmpmsg = general.ReplyDefaultStr
    else:
        tmpmsg = ''.join(open(config.filewithreply).readlines())
    msg = heads + tmpmsg
    serv.sendmail(fromaddr, toaddr, msg)
    aprint(_("Reply succesfully send to %s") % toaddr, general.VIOLET)

    # It's necessary to always lock the write access to the repliedList since
    # is used globally
    AnimailMain.Application.repLock.acquire()
    AnimailMain.Application.repliedList.append(toaddr)
    AnimailMain.Application.release_repLock()
    serv.quit()
Example #35
0
def email_to_job(msg):
    logging.info("looking at email with subject: %s", msg['subject'])

    if not is_job_email(msg):
        return None

    if Job.objects.filter(email_message_id=msg['message-id']).count() == 1:
        return None

    logging.info("parsing job email %s", msg['message-id'])

    j = Job()
    j.contact_name, j.contact_email = rfc822.parseaddr(msg['from'])
    j.contact_name = normalize_name(j.contact_name)
    j.contact_email = j.contact_email.lower()

    # get the employer
    #j.from_domain = j.from_address.split('@')[1]

    j.title = re.sub("^\[CODE4LIB\] ", "", msg['subject'])
    j.title = re.sub("[\n\r]", "", j.title)
    j.email_message_id = msg['message-id']
    j.description = get_html(get_body(msg))

    t = time.mktime(rfc822.parsedate(msg['date']))
    j.post_date = datetime.datetime.fromtimestamp(t)

    if not j.description:
        logging.warn("missing body")
        return None

    j.save()

    # automatically assign subjects based on keywords in the job description
    for n in nouns(j.description):
        n = n.lower()
        for subject in Subject.objects.filter(keywords__name=n):
            j.subjects.add(subject)

    j.save()
    return j
Example #36
0
 def write_mbox(self, mbox, header, body, fromm):
     try:
             fcntl.flock(mbox.fileno(), fcntl.LOCK_EX)
             mbox.seek(0,2)
             (foo,emailaddr) = rfc822.parseaddr(fromm)
             strfromm = 'From %s' % emailaddr + ' ' + general.take_date() + '\n'
             mbox.write(strfromm)
             if self.__class__.__name__ != "Pop3Server":
                         mbox.write(header)
             if body[:-1] != '\n': body += '\n'
             mbox.write(self.process_body(body))
             mbox.flush()
             fcntl.flock(mbox.fileno(), fcntl.LOCK_UN)
             mbox.close()
     except IOError, x:
             try:
                         fcntl.flock(mbox.fileno(), fcntl.LOCK_UN)
                         mbox.close()
             except:
                         pass
             raise mboxException, _("Failure writing to mbox file '%s' (%s)") % (mbox.name,x)
Example #37
0
    def parse_email(self, email_info):
        try:
            import rfc822
        except ImportError:
            import email.utils as rfc822

        name, email = rfc822.parseaddr(email_info)

        # more than likely a string was passed here instead of an email address
        if "@" not in email:
            name = email
            email = None

        if not name:
            name = None

        if not email:
            email = None

        self.name = name
        self.email = email
        return name, email
Example #38
0
    def __init__(self, id, from_addr, subject, date=None, **kwargs):
        from_addr = from_addr.decode('utf-8', 'replace')
        self.from_addr = decode_header(email.Header.Header(from_addr))

        subject = subject.decode('utf-8', 'replace')
        self.subject = decode_header(email.Header.Header(subject))
        # date is expected to be a DateTime or None
        if not isinstance(date, DateTime):
            self.date = DateTime(date)
        else:
            self.date = date

        sender_name = parseaddr(self.from_addr)[0]

        title_subj = len(self.subject) > 20 and (self.subject[:20]+' ...') \
                         or self.subject
        if sender_name:
            self.title = u"%s / %s" % (title_subj, sender_name)
        else:
            self.title= title_subj

        Folder.__init__(self, id)
Example #39
0
def email_to_job(msg):
    logging.info("looking at email with subject: %s", msg['subject'])

    if not is_job_email(msg):
        return None

    if Job.objects.filter(email_message_id=msg['message-id']).count() == 1:
        return None

    logging.info("parsing job email %s", msg['message-id'])

    j = Job()
    j.contact_name, j.contact_email = rfc822.parseaddr(msg['from'])
    j.contact_name = normalize_name(j.contact_name)
    j.contact_email = j.contact_email.lower()

    # get the employer
    #j.from_domain = j.from_address.split('@')[1]

    j.title = re.sub("^\[CODE4LIB\] ", "", msg['subject'])
    j.title = re.sub("[\n\r]", "", j.title)
    j.email_message_id = msg['message-id']
    j.description = get_html(get_body(msg))

    t = time.mktime(rfc822.parsedate(msg['date']))
    j.post_date = datetime.datetime.fromtimestamp(t)

    if not j.description:
        logging.warn("missing body")
        return None

    if 'http://jobs.code4lib.org' in j.description:
        logging.warn("not loading a job that shortimer posted")
        return None

    j.save()
    autotag(j)
    j.save()
    return j
Example #40
0
    def parse_email(self, email_info):
        """Allows passing emails as "Example Name <*****@*****.**>"

        :param email_info: Allows passing emails as
                           "Example Name <*****@*****.**>"
        :type email_info: string
        """
        name, email = rfc822.parseaddr(email_info)

        # more than likely a string was passed here instead of an email address
        if "@" not in email:
            name = email
            email = None

        if not name:
            name = None

        if not email:
            email = None

        self.name = name
        self.email = email
        return name, email
Example #41
0
    def _checkStateMX(self):
        nextMessages = self.queue.getWaiting()
        nextMessages.reverse()

        exchanges = {}
        for msg in nextMessages:
            from_, to = self.queue.getEnvelope(msg)
            name, addr = rfc822.parseaddr(to)
            parts = addr.split('@', 1)
            if len(parts) != 2:
                log.err("Illegal message destination: " + to)
                continue
            domain = parts[1]

            self.queue.setRelaying(msg)
            exchanges.setdefault(domain, []).append(self.queue.getPath(msg))
            if len(exchanges) >= (self.maxConnections - len(self.managed)):
                break

        if self.mxcalc is None:
            self.mxcalc = MXCalculator()

        relays = []
        for (domain, msgs) in exchanges.iteritems():
            manager = _AttemptManager(self)
            factory = self.factory(msgs, manager, *self.fArgs, **self.fKwArgs)
            self.managed[factory] = map(os.path.basename, msgs)
            relayAttemptDeferred = manager.getCompletionDeferred()
            connectSetupDeferred = self.mxcalc.getMX(domain)
            connectSetupDeferred.addCallback(lambda mx: str(mx.name))
            connectSetupDeferred.addCallback(self._cbExchange, self.PORT,
                                             factory)
            connectSetupDeferred.addErrback(
                lambda err: (relayAttemptDeferred.errback(err), err)[1])
            connectSetupDeferred.addErrback(self._ebExchange, factory, domain)
            relays.append(relayAttemptDeferred)
        return DeferredList(relays)
Example #42
0
        def look_message(self,msg, logAgent, indice_log, left, smtpobj):
            """ Look a message header and delete it if matchs some regular expresion
            of the list given by the user in the filterfile.
            """
            #FIXME: This need reorganization
            # Some alias to optimize the "for patron in lfilters" loop
            # (yeah, this speed up things a lot)
            optnotlog = self.config.optnotlog
            lfilters = self.config.lfilters
            lfilterscomp = self.config.lfilterscomp
            laccepted = self.config.laccepted
            lacceptedcomp = self.config.lacceptedcomp
            laterReply = False
            isConfirmation = False
            notAccepted = False
            resultWUIMAP = None

            re_compile = re.compile

            if self.config.optsize and (msg['size'] >= self.config.max_size):
                    aprint(_("Message %d size exceed limit (%d), deleting it") % (msg['orignumber'], self.config.max_size), general.RED)
                    if not optnotlog:
                                logAgent.incident(indice_log, _("Message %d deleted, size limit reached") %
                                                        msg['orignumber'])
                    self.server_bytes_left = self.server_bytes_left - msg['size']
                    self.delmesg(msg)
                    return ('delete', None, None)

            listacab = self.get_header(msg, left)

            #FIXME: This is protocol-dependent, don't fit in the base class...
            if self.protocol == 'POP3':
                    header = '\n'.join(listacab[1])
            elif self.protocol == 'IMAP4': header = listacab

            rfcObj = rfc822.Message(StringIO.StringIO(header))
            fromwho = rfcObj.getheader('From')
            (foo,emailaddr) = rfc822.parseaddr(fromwho)

            # Check if the message is one of those pesky 'DON'T DELETE THIS MESSAGE, FOLDER INTERNAL DATA'
            if msg['orignumber'] == 1:
                resultWUIMAP = re_wuimap.search(header)
                if resultWUIMAP is not None:
                    aprint(_("Ignoring message %d: DONTDELETETHISMESSAGE type message") % (msg['orignumber']), general.RED)
                    return ('wuimap', None, fromwho)

            if self.config.notInAccept == 'reply':
                    (foo,emailaddrReply) = rfc822.parseaddr(self.config.replyaddress.strip())
                    comp = re_compile('Subject:' + '.*' + self.config.replysubject + ' ' + '\[' + emailaddrReply + '\]' , re.M)
                    isMatch = comp.search(header)

                    if isMatch is not None: #it's a reply to an Animail message
                                aprint(_("We've an address confirmation from %s, recovering postergated messages") % fromwho, general.VIOLET)
                                self.recoverDelayed(emailaddr, smtpobj)
                                if self.config.autoacceptconfirm:
                                    faccept = open(self.config.nacceptfile, 'a+')
                                    faccept.seek(0,2)
                                    faccept.write(emailaddr)
                                    faccept.write('\n')
                                    aprint(_("%s Address added to auto-accept file") % emailaddr,general.VIOLET)
                                    try:
                                        smtp.generateConfirmation(emailaddr)
                                    except smtplib.SMTPException, x:
                                        aprint(_("SMTP Error delivering confirmation to %s, reply not sent: %s") % (fromwho, x), general.RED)
                                isConfirmation = True
Example #43
0
 def set_from(self, from_email):
     name, email = rfc822.parseaddr(from_email.replace(',', ''))
     if email:
         self.from_email = email
     if name:
         self.set_from_name(name)
Example #44
0
 def parse_and_add(self, to):
     name, email = rfc822.parseaddr(to.replace(',', ''))
     if email:
         self.to.append(email)
     if name:
         self.add_to_name(name)
Example #45
0
        def get_messages(self, logAgent, indice_log, is_retry, smtp):
            nmesg = len(self.lmsg)
            general.cursor_off()
            header = ''
            fromwho = ''

            if self.delivery == 'mta':
                    deliver = self.deliver_smtp
            elif self.delivery == 'mbox':
                    deliver = self.deliver_mbox
            elif self.delivery == 'maildir':
                    deliver = self.deliver_maildir
            elif self.delivery == 'pipe':
                    deliver = self.deliver_pipe
            elif self.delivery == 'global':
                    if self.config.optsmtp:
                                deliver = self.deliver_smtp
                    elif self.config.optmbox:
                                deliver = self.deliver_mbox
                    elif self.config.optmaildir:
                                deliver = self.deliver_maildir
                    elif self.config.optsendmail:
                                deliver = self.deliver_pipe

            num_trans = 0
            retcode = 'pass'
            for msg in self.lmsg[:]:
                    must_deliver = True
                    num_trans += 1
                    (size, unit) = general.compute(msg['size'])

                    if not self.config.optsyslog:
                                aprint('-'* 21, general.GREEN)
                    if self.config.optexpresion:
                                (retcode, header, fromwho) = self.look_message(msg,logAgent,indice_log,nmesg - num_trans,smtp)
                                if retcode == 'delete': #Deleted
                                    if self.config.optsmtp:
                                            smtp.smtpobj.noop()
                                    continue
                    # end if self.config.optexpresion

                    aprint(_("Downloading message %d (%.2f %s), Left: %d (%s)") % (msg['orignumber'], size, unit, nmesg - num_trans, self.alias),general.VIOLET)
                    
                    (msgbody, fromm, tmpheader) = self.get_message(msg, smtp, header, nmesg)
                    if fromm != '' and fromwho == '':
                                fromwho = fromm

                    if tmpheader != '':
                                header = tmpheader

                    if not self.config.optsyslog and not self.config.optquiet:
                                sys.stderr.write(general.colorize(_("\rDownloaded: "),general.YELLOW))
                                sys.stderr.write(general.colorize("100%\n",general.WHITE))


                    # If self.config.optexpression we've already looked for the IMAP
                    # DONTDELETETHISMESSAGE messages in the look_header method
                    if not self.config.optexpresion:
                        if msg['orignumber'] == 1:
                            resultWUIMAP = re_wuimap.search(msgbody)
                            resultWUIMAP2 = re_wuimap.search(header)
                            if (resultWUIMAP is not None) or (resultWUIMAP2 is not None):
                                aprint(_("Ignoring message %d: DONTDELETETHISMESSAGE type message") % (msg['orignumber']), general.RED)
                                retcode = 'wuimap'

                    if retcode == 'wuimap': must_deliver = False

                    try:
                                if retcode == 'postergate': #Message delayed
                                    animailBoxPath = self.config.homedir + '/.animail/animailDelayed'
                                    if not os.path.exists(animailBoxPath):
                                            os.mkdir(animailBoxPath, 0700)
                                    (foo,emailaddress) = rfc822.parseaddr(fromwho)
                                    tmpbox = open(animailBoxPath + '/' + emailaddress, 'a+')
                                    self.write_mbox(tmpbox, header, msgbody, fromm)
                                else:
                                    if retcode != 'wuimap': must_deliver = True
                                    if (self.config.lpostfilters != []) and (retcode != 'wuimap'):
                                        #FIXME SESSION: En realidad sólo sería necesario pasarle al
                                        #postfiltro el msgstr; después este, en su método
                                        #filter_mail ya se encargaría de crear el archivo temporal,
                                        #y sólo de ser necesario (si el filtro tiene opciones y
                                        #si estas opciones contienen un %M).

                                        #el create_msgstr también podría ir en el postfiltro pero
                                        #depende de la subclase de mailserver (pop3 o imap4). Eso
                                        #habría que arreglarlo definitivamente para que en la clase
                                        #base no se depende del tipo, quizás añadiendo un método a
                                        #las clases derivadas header_and_body o algo así.
                                        
                                        msgstr = self.create_msgstr(header,msgbody)
                                        tmpfile = open(tempfile.mktemp(), 'w+')
                                        os.chmod(tmpfile.name, 0600)
                                        tmpfile.write(msgstr)

                                        # Number of filters that have matched this message:
                                        npositives = 0
                                        # Have we copied this email to the spambox yet?
                                        alreadycopied = 0
                                        for pfilter in self.config.lpostfilters:
                                            output = ''
                                            aprint(_("Executing postfilter %s on message...") % pfilter.filtername, general.YELLOW)
                                            (pretcode, output) = pfilter.filter_mail(msgstr,tmpfile.name)
                                            if pretcode == 1:
                                                # Matched!
                                                npositives += 1

                                                if self.config.allpostfilters and ( npositives != len( self.config.lpostfilters) ):
                                                        # allpostfilters needs all the postfilters to match a 
                                                        # message for having it filtered:
                                                        continue

                                                must_deliver = False
                                                if not self.config.optnotlog: logAgent.append_filtered(indice_log,_("%s (Postfiltered by'%s')")%(fromm,pfilter.filtername),msg['size'])
                                                if pfilter.savepostfilteredmails != 0 and not alreadycopied:
                                                    pfilter.log_filtered_mail(msgstr,fromm, output)
                                                    alreadycopied = 1
                                                if npositives >= self.config.minpostfilters:
                                                    break
                                        tmpfile.close()
                                        os.unlink(tmpfile.name)
                                    if must_deliver:
                                        deliver(header, msgbody, fromm, smtp)

                                if self.optdelete and retcode != 'wuimap':
                                    aprint(_("Deleting message"), general.YELLOW)
                                    self.delmesg(msg)
                    except SMTPException, x:
                                print
                                print _("The local SMTP rejected this message so it won't be deleted from the mail server:"), str(x)
                                smtp.quit()
                                smtp.connect()
                                if not self.config.optnotlog:
                                    logAgent.incident(indice_log, str(x))
                    except socket.error, x:
                                print
                                print _("Socket error sending to the local SMTP, it won't be deleted from the mail server:"), str(x)
                                try:
                                    smtp.quit()
                                    smtp.connect()
                                except AttributeError: pass
                                if not self.config.optnotlog:
                                    logAgent.incident(indice_log, str(x))
                                continue
Example #46
0
def msg_parse(env_from, msg):
	msg_parsed = email.message_from_string(msg)
	(env_to_name, env_to_addr) = rfc822.parseaddr(msg_parsed['To'])
	return env_from, env_to_addr, msg
Example #47
0
def process_msg(msg):
	msg = email.message_from_string('\n'.join(msg))
	(listname, list_addr) = rfc822.parseaddr(msg['To'])
	try:
		mlist = MailingList.objects.get(listaddress__iexact=list_addr)
	except MailingList.DoesNotExist:
		print >>sys.stderr, 'Mailing list %s does not exist' % msg['To']
		return False

	swimmer_set = [ s.user.email for s in mlist.swimmers.all() ]
	newmsg = msg
	try:
		newmsg.replace_header('Reply-To', msg['From'])
	except KeyError:
		newmsg.add_header('Reply-To', msg['From'])
		
	""" Two things. 1. Check that the sender is on the list they are sending to. 2. Save a copy of the message """
	""" FIXME: I have a feeling that broken email clients are going to pass through mangled from headers """
	(realname, from_email) = rfc822.parseaddr(msg['From'])
	
	rfc_from = ''
	swimmer = None
	""" The reason for this check is that we want certain automatic scripts to be able to mail lists.  dev@ uses this """
	
	if from_email != list_addr:
		try:
			swimmer = Swimmer.objects.get(user__email__iexact=from_email)
		except Swimmer.DoesNotExist:
			print >>sys.stderr, 'didn\'t find swimmer with email address = %s' % from_email
			return False
		rfc_from = rfc822.dump_address_pair(('%s %s' %( swimmer.user.first_name, 
			swimmer.user.last_name), swimmer.user.email))
	else:
		rfc_from = rfc822.dump_address_pair(('', list_addr))
	
	body = ''
	if msg.is_multipart():
		for b in msg.get_payload():
			if b.get_content_type() == 'text/plain':
				body = b.get_payload()
				break
			elif b.get_content_type() == 'text/html':
				body = b.get_payload()
				stripper = Stripper()
				try:
					body = stripper.strip(body)
				except: #Sometimes the html is just a mess
					body = re.sub('<.*?>', '', body)
				break
	else:
		body = msg.get_payload()
	if swimmer != None:
		try:
			m = Message(fromswimmer=swimmer, tolist=mlist, message=body, subject=msg['Subject'])
			m.save()
		except:
			print >>sys.stderr, 'Message save failed on body = %s and subject = %s' %( body, msg['Subject'])
	
	s = smtplib.SMTP()
	s.connect(settings.OUTGOING_MAIL_HOST)

	failed_hash = {}

	try: 
		failed_hash = s.sendmail(rfc_from, swimmer_set, newmsg.as_string())
	except smtplib.SMTPRecipientsRefused, e:
		print >>sys.stderr, 'recipients refused %s' %e
Example #48
0
def save_list_message(lines, mailinglist):
	msg = email.message_from_string('\n'.join(lines))
	(listname, list_addr) = rfc822.parseaddr(msg['To'])
	""" This is fairly simple in here. validate, save, and look up mx record and
	then use the smtp.send() method 
	"""
	print 'mailinglist: %s to: %s' % ( mailinglist, msg['To'])
	try:
		swimmer_set = [ s.user.email for s in mailinglist.swimmers.all() ]
	except:
		raise Exception('oops failed to send on null mailing list %s ' % msg['To'] ) 
		
	newmsg = msg
	try:
		newmsg.replace_header('Reply-To', msg['From'])
	except KeyError:
		newmsg.add_header('Reply-To', msg['From'])

		
	""" Two things. 1. Check that the sender is on the list they are sending to. 2. Save a copy of the message """
	""" FIXME: I have a feeling that broken email clients are going to pass through mangled from headers """
	(realname, from_email) = rfc822.parseaddr(msg['From'])
        
	swimmer = None
	""" The reason for this check is that we want certain automatic scripts to be able to mail lists.  dev@ uses this """
	
	if from_email != mailinglist.listaddress:
                """ Okay so we set the FROM header to the mailing list and make sure the env_from matches it"""
                newmsg.replace_header('From', mailinglist.listaddress)
                """ First thing we check is whether only board members can post.  If so throw the
                message out if the from isn't a board member"""
                if mailinglist.board_postable_only:
                    try:
                        bm = BoardMember.objects.get(swimmer__email__iexact=from_email)
                    except BoardMember.DoesNotExist:
                        raise Exception('Only board members can post to this list %s' % from_email)
		try:
			swimmer = Swimmer.objects.get(user__email__iexact=from_email)
		except Swimmer.DoesNotExist:
			raise Exception('didn\'t find swimmer with email address = %s' % from_email)
	
        env_from = list_addr
	
	body = ''
	if msg.is_multipart():
		for b in msg.get_payload():
			if b.get_content_type() == 'text/plain':
				body = b.get_payload()
				break
			elif b.get_content_type() == 'text/html':
				body = b.get_payload()
				stripper = Stripper()
				try:
					body = stripper.strip(body)
				except: #Sometimes the html is just a mess
					body = re.sub('<.*?>', '', body)
				break
	else:
		body = msg.get_payload()
	if swimmer != None:
		try:
			m = RTMessage.objects.create(fromswimmer=swimmer, tolist=mailinglist, message=unicode(body, 'utf-8'), subject=msg['Subject'])
		except Exception, e:
			print >>sys.stderr, 'Message save failed like %s on body = %s and subject = %s' %( e, body, msg['Subject'])
Example #49
0
 def get_mailbox_for_message(self, message):
     email_address = rfc822.parseaddr(message['to'])[1][0:255]
     return self.get_mailbox_by_name(email_address)
Example #50
0
def parseOptions(argv):
    o = Options()
    o.to = [e for e in argv if not e.startswith('-')]
    o.sender = getlogin()

    # Just be very stupid

    # Skip -bm -- it is the default

    # -bp lists queue information.  Screw that.
    if '-bp' in argv:
        raise _unsupportedOption

    # -bs makes sendmail use stdin/stdout as its transport.  Screw that.
    if '-bs' in argv:
        raise _unsupportedOption

    # -F sets who the mail is from, but is overridable by the From header
    if '-F' in argv:
        o.sender = argv[argv.index('-F') + 1]
        o.to.remove(o.sender)

    # -i and -oi makes us ignore lone "."
    if ('-i' in argv) or ('-oi' in argv):
        raise _unsupportedOption

    # -odb is background delivery
    if '-odb' in argv:
        o.background = True
    else:
        o.background = False

    # -odf is foreground delivery
    if '-odf' in argv:
        o.background = False
    else:
        o.background = True

    # -oem and -em cause errors to be mailed back to the sender.
    # It is also the default.

    # -oep and -ep cause errors to be printed to stderr
    if ('-oep' in argv) or ('-ep' in argv):
        o.printErrors = True
    else:
        o.printErrors = False

    # -om causes a copy of the message to be sent to the sender if the sender
    # appears in an alias expansion.  We do not support aliases.
    if '-om' in argv:
        raise _unsupportedOption

    # -t causes us to pick the recipients of the message from the To, Cc, and Bcc
    # headers, and to remove the Bcc header if present.
    if '-t' in argv:
        o.recipientsFromHeaders = True
        o.excludeAddresses = o.to
        o.to = []
    else:
        o.recipientsFromHeaders = False
        o.exludeAddresses = []

    requiredHeaders = {
        'from': [],
        'to': [],
        'cc': [],
        'bcc': [],
        'date': [],
    }

    headers = []
    buffer = StringIO.StringIO()
    while 1:
        write = 1
        line = sys.stdin.readline()
        if not line.strip():
            break

        hdrs = line.split(': ', 1)

        hdr = hdrs[0].lower()
        if o.recipientsFromHeaders and hdr in ('to', 'cc', 'bcc'):
            o.to.extend(
                [a[1] for a in rfc822.AddressList(hdrs[1]).addresslist])
            if hdr == 'bcc':
                write = 0
        elif hdr == 'from':
            o.sender = rfc822.parseaddr(hdrs[1])[1]

        if hdr in requiredHeaders:
            requiredHeaders[hdr].append(hdrs[1])

        if write:
            buffer.write(line)

    if not requiredHeaders['from']:
        buffer.write('From: %s\r\n' % (o.sender, ))
    if not requiredHeaders['to']:
        if not o.to:
            raise SystemExit("No recipients specified.")
        buffer.write('To: %s\r\n' % (', '.join(o.to), ))
    if not requiredHeaders['date']:
        buffer.write('Date: %s\r\n' % (smtp.rfc822date(), ))

    buffer.write(line)

    if o.recipientsFromHeaders:
        for a in o.excludeAddresses:
            try:
                o.to.remove(a)
            except:
                pass

    buffer.seek(0, 0)
    o.body = StringIO.StringIO(buffer.getvalue() + sys.stdin.read())
    return o
Example #51
0
                    fh.write(message)
                    fh.close()
                    ewrite('Draft saved into %s\n', msgname)
                    succeeded = True
            else:
                succeeded = True

    elif not failed and (using_sendmail or smtphost):
        if kudos:
            ewrite('\nMessage sent to: %s\n', sendto)
        else:
            ewrite("\nBug report submitted to: %s\n", sendto)

        addresses = []
        for addr in alist:
            if addr[1] != rfc822.parseaddr(sendto)[1]:
                addresses.append(addr)

        if len(addresses):
            ewrite("Copies sent to:\n")
            for address in addrs:
                ewrite('  %s\n', address)

        if debbugs_cc and rtype == 'debbugs':
            ewrite("Copies will be sent after processing to:\n")
            for address in cclist:
                ewrite('  %s\n', address)

    if not (exinfo or kudos) and rtype == 'debbugs' and sysinfo and not failed:
        ewrite('\n')
        ui.long_message(
Example #52
0
    def _build_sg_mail(self, email):
        mail = Mail()
        from_name, from_email = rfc822.parseaddr(email.from_email)
        # Python sendgrid client should improve
        # sendgrid/helpers/mail/mail.py:164
        if not from_name:
            from_name = None

        mail.from_email = Email(from_email, from_name)

        mail.subject = email.subject

        personalization = Personalization()
        for e in email.to:
            personalization.add_to(Email(e))
        for e in email.cc:
            personalization.add_cc(Email(e))
        for e in email.bcc:
            personalization.add_bcc(Email(e))
        personalization.subject = email.subject
        mail.add_content(Content("text/plain", email.body))
        if isinstance(email, EmailMultiAlternatives):
            for alt in email.alternatives:
                if alt[1] == "text/html":
                    mail.add_content(Content(alt[1], alt[0]))
        elif email.content_subtype == "html":
            mail.contents = []
            mail.add_content(Content("text/plain", ' '))
            mail.add_content(Content("text/html", email.body))

        if hasattr(email, 'categories'):
            for c in email.categories:
                mail.add_category(Category(c))

        if hasattr(email, 'template_id'):
            mail.template_id = email.template_id
            if hasattr(email, 'substitutions'):
                for k, v in email.substitutions.items():
                    personalization.add_substitution(Substitution(k, v))

        if hasattr(email, 'custom_args'):
            for item in email.custom_args:
                for k, v in item.items():
                    mail.add_custom_arg(CustomArg(k, v))

        for k, v in email.extra_headers.items():
            mail.add_header({k: v})

        for attachment in email.attachments:
            if isinstance(attachment, MIMEBase):
                attach = Attachment()
                attach.filename = attachment.get_filename()
                attach.content = base64.b64encode(attachment.get_payload())
                mail.add_attachment(attach)
            elif isinstance(attachment, tuple):
                attach = Attachment()
                attach.filename = attachment[0]
                base64_attachment = base64.b64encode(attachment[1])
                if sys.version_info >= (3,):
                    attach.content = str(base64_attachment, 'utf-8')
                else:
                    attach.content = base64_attachment
                attach.type = attachment[2]
                mail.add_attachment(attach)

        mail.add_personalization(personalization)
        return mail.get()
Example #53
0
                                print _("Socket error sending to the local SMTP, it won't be deleted from the mail server:"), str(x)
                                try:
                                    smtp.quit()
                                    smtp.connect()
                                except AttributeError: pass
                                if not self.config.optnotlog:
                                    logAgent.incident(indice_log, str(x))
                                continue
                    except mboxException, x:
                                print
                                print _("CRITICAL ERROR. There was an error delivering to MBox, aborting, message won't be deleted from the mail server: "), str(x)
                                sys.exit(1)
                    except maildirException, x:
                                print
                                print _("CRITICAL ERROR. There was an error delivering to Maildir, aborting, message won't be deleted from the mail server: "), str(x)
                                sys.exit(1)
                    except socket.sslerror, x:
                                print
                                print _("Socket error on SSL connection:"), str(x)


                    if not self.config.optnotlog and must_deliver:
                        (foo,emailaddr) = rfc822.parseaddr(fromm)
                        logAgent.append_downloaded(indice_log, emailaddr, msg['size'])

            if not self.config.optsyslog:
                    aprint('-'* 21, general.GREEN)
            general.cursor_on()
#********************************************************************************

Example #54
0
def detach(msg):
    # quick exit if we have seen this entry before
    if not msg['message-id']: return
    id = md5(msg['message-id']).hexdigest()
    if os.path.exists(os.path.join('tally', id)): return

    # known spammers
    if '<*****@*****.**>' in msg['from']:
        return

    # collect eligible attachments
    attachments = []
    for payload in msg.get_payload():

        # progress into multipart/mixed
        if payload.get_content_type() == 'multipart/mixed':
            payload = payload.get_payload()
        else:
            payload = [payload]

        # iterate over (possibly nested) attachments
        for subpayload in payload:
            if subpayload.get_content_type() in skip:
                if subpayload.get_filename() not in forms: continue
                content = subpayload.get_payload(decode=True)
                if 'License Agreement' not in content and \
                  '-----BEGIN PGP SIGNATURE-----' not in content:
                    continue
            if subpayload.get_content_type() == 'image/gif':
                if len(subpayload.get_payload(decode=True)) < 10240: continue
            # if not subpayload.get_payload(decode=True): continue

            # get_filename doesn't appear to have an endswith method
            # if subpayload.get_filename().endswith('.gpg'): continue
            attachments.append(subpayload)

    if len(attachments) == 0: return

    if os.system('svn update received') != 0:
        return

    ## COMMENTED OUT - AS SPAMC IS NOT INSTALLED HERE
    #
    # if 'eFax message from' not in decode(msg['subject']):
    #   msg = analyze(msg)
    #   if msg.spam:
    #     attachments = []

    # determine output file name prefix
    prefix = ''
    if len(attachments) > 1:
        prefix = rfc822.parseaddr(decode(msg['from']).decode('utf-8'))[1]
        received = os.path.join('received', prefix)
        if (not re.match(r'^[.@\w]+$', prefix)) or os.path.exists(received):
            dirname = datetime(
                *email.utils.parsedate(msg['date'])[:7]).isoformat()
            prefix = dirname.replace(':', '_').replace('-', '_')
            received = os.path.join('received', prefix)
        if not os.path.exists(received): os.mkdir(received)
        svn('add', received)
        prefix += os.sep
    elif len(attachments) == 1:
        name = asciize(decode(attachments[0].get_filename()))
        if not name: return
        if attachments[0].get_content_type() in sigs: return
        if len(name) < 16:
            prefix = decode(msg['from'])
            if prefix.startswith('"eFax"'):
                prefix = 'eFax'
            else:
                prefix = asciize(prefix)
                if prefix.find('<') >= 0: prefix = prefix.split('<')[1]
                prefix = prefix.split('@')[0]
            prefix = prefix + '-'
        try:
            name.decode('utf-8')
        except:
            name = name.decode('iso-8859-1').encode('utf-8')

    # determine commit message
    summary = "\n".join([
        'Subject: ' + decode(msg['subject']),
        'From: ' + decode(msg['from']),
        'Date: ' + str(msg['date']),
        'Message-Id: ' + str(msg['message-id']),
        'X-Spam-Status' + str(msg['X-Spam-Status']),
    ])

    count = 0
    file = None

    # decode payloads and place add to svn
    for attachment in attachments:
        mime = attachment.get_content_type()
        if mime == 'application/octet-stream':
            mime = mimetypes.guess_type(decode(attachment.get_filename()))[0]
        name = asciize(decode(attachment.get_filename()))
        if name == 'none':
            name = str(dict(attachment.get_params()).get('name'))

        content = attachment.get_payload(decode=True)
        if content:
            file = os.path.join('received', (prefix + name).strip('-'))
            if os.path.isdir(file): file = os.path.join(file, 'unnamed')
            fh = open(file, 'w')
            fh.write(content)
            fh.close()

            svn('add', file)
            if mime: svn('propset svn:mime-type ' + mime, file)
            count = count + 1

    if count > 1: file = os.path.join('received', prefix.strip('-'))

    try:
        name = decode(msg['from'], 0)
        try:
            addr = rfc822.parseaddr(decode(msg['from'], 1))[1]
        except:
            name, addr = rfc822.parseaddr(name)

        if name != 'eFax' and file:
            props = {
                'email:id': msg['message-id'],
                'email:subject': re.sub(r'\n\s*', ' ', decode(msg['subject']))
            }
            if name: props['email:name'] = name
            if addr: props['email:addr'] = addr
            if msg['cc']:
                props['email:cc'] = re.sub('\s+', ' ', decode(msg['cc']))
            for (key, value) in props.items():
                svn('propset ' + key + ' ' + repr(value), file)
    except:
        pass

    tally = os.path.join('tally', id)
    fh = open(tally, 'w')
    fh.write(summary + "\n")
    fh.close()

    if count > 0 and getpass.getuser() != 'www-data':
        if svn('commit --file ' + tally, file) != 0:
            return  # try again next cron cycle
Example #55
0
def do_table(status, merges, left_distro, right_distro, component):
    """Output a table."""
    print("<table cellspacing=0>", file=status)
    print("<tr bgcolor=#d0d0d0>", file=status)
    print("<td rowspan=2><b>Package</b></td>", file=status)
    print("<td colspan=2><b>Last Uploader</b></td>", file=status)
    print("<td rowspan=2><b>Comment</b></td>", file=status)
    print("<td rowspan=2><b>Bug</b></td>", file=status)
    print("</tr>", file=status)
    print("<tr bgcolor=#d0d0d0>", file=status)
    print("<td><b>%s Version</b></td>" % left_distro.title(), file=status)
    print("<td><b>%s Version</b></td>" % right_distro.title(), file=status)
    print("</tr>", file=status)

    for uploaded, priority, package, user, uploader, source, \
            left_version, right_version in merges:
        if user is not None:
            who = user
            who = who.replace("&", "&amp;")
            who = who.replace("<", "&lt;")
            who = who.replace(">", "&gt;")

            if uploader is not None:
                (usr_name, usr_mail) = parseaddr(user)
                (upl_name, upl_mail) = parseaddr(uploader)

                if len(usr_name) and usr_name != upl_name:
                    u_who = uploader
                    u_who = u_who.replace("&", "&amp;")
                    u_who = u_who.replace("<", "&lt;")
                    u_who = u_who.replace(">", "&gt;")

                    who = "%s<br><small><em>Uploader:</em> %s</small>" \
                            % (who, u_who)
        else:
            who = "&nbsp;"

        print("<tr bgcolor=%s class=first>" % COLOURS[priority], file=status)
        print("<td><tt><a href=\"https://patches.tanglu.org/" \
              "%s/%s/%s_%s.patch\">%s</a></tt>" \
              % (pathhash(package), package, package, left_version, package),
              file=status)
        print(" <sup><a href=\"https://launchpad.net/ubuntu/" \
              "+source/%s\">LP</a></sup>" % package, file=status)
        print(" <sup><a href=\"http://packages.qa.debian.org/" \
              "%s\">PTS</a></sup></td>" % package, file=status)
        print("<td colspan=2>%s</td>" % who, file=status)
        print(
            "<td rowspan=2><form method=\"get\" action=\"addcomment.py\"><br />",
            file=status)
        print(
            "<input type=\"hidden\" name=\"component\" value=\"%s-manual\" />"
            % component,
            file=status)
        print("<input type=\"hidden\" name=\"package\" value=\"%s\" />" %
              package,
              file=status)
        print("<%%\n\
the_comment = \"\"\n\
if \"%s\" in comment:\n\
    the_comment = comment[\"%s\"]\n\
req.write(\"<input type=\\\"text\\\" style=\\\"border-style: none; background-color: %s\\\" name=\\\"comment\\\" value=\\\"%%s\\\" title=\\\"%%s\\\" />\" %% (the_comment, the_comment))\n\
%%>" % (package, package, COLOURS[priority]),
              file=status)
        print("</form></td>", file=status)
        print("<td rowspan=2>", file=status)
        print("<%%\n\
if \"%s\" in comment:\n\
    req.write(\"%%s\" %% gen_buglink_from_comment(comment[\"%s\"]))\n\
else:\n\
    req.write(\"&nbsp;\")\n\
\n\
%%>" % (package, package),
              file=status)
        print("</td>", file=status)
        print("</tr>", file=status)
        print("<tr bgcolor=%s>" % COLOURS[priority], file=status)
        print("<td><small>%s</small></td>" % source["Binary"], file=status)
        print("<td>%s</td>" % left_version, file=status)
        print("<td>%s</td>" % right_version, file=status)
        print("</tr>", file=status)

    print("</table>", file=status)
Example #56
0
def decode_sender(sender):
    """Decode UTF-8 base64 etc headers.  decode_header() must be able to do
    this on its own, but due to a bug it fails to process multiline values."""
    sender = decode_value(sender)
    return rfc822.parseaddr(sender.replace("\r\n", ""))
Example #57
0
        def get_messages(self, logAgent, indice_log, is_retry, smtp):
            nmesg = len(self.lmsg)
            general.cursor_off()
            header = ''
            fromwho = ''

            if self.delivery == 'mta':
                    deliver = self.deliver_smtp
            elif self.delivery == 'mbox':
                    deliver = self.deliver_mbox
            elif self.delivery == 'maildir':
                    deliver = self.deliver_maildir
            elif self.delivery == 'pipe':
                    deliver = self.deliver_pipe
            elif self.delivery == 'global':
                    if self.config.optsmtp:
                                deliver = self.deliver_smtp
                    elif self.config.optmbox:
                                deliver = self.deliver_mbox
                    elif self.config.optmaildir:
                                deliver = self.deliver_maildir
                    elif self.config.optsendmail:
                                deliver = self.deliver_pipe

            num_trans = 0
            retcode = 'pass'
            for msg in self.lmsg[:]:
                    must_deliver = True
                    num_trans += 1
                    (size, unit) = general.compute(msg['size'])

                    if not self.config.optsyslog:
                                aprint('-'* 21, general.GREEN)
                    if self.config.optexpresion:
                                (retcode, header, fromwho) = self.look_message(msg,logAgent,indice_log,nmesg - num_trans,smtp)
                                if retcode == 'delete': #Deleted
                                    if self.config.optsmtp:
                                            smtp.smtpobj.noop()
                                    continue
                    # end if self.config.optexpresion

                    aprint(_("Downloading message %d (%.2f %s), Left: %d") % (msg['orignumber'], size, unit, nmesg - num_trans),general.VIOLET)
                    
                    (msgbody, fromm, tmpheader) = self.get_message(msg, smtp, header, nmesg)
                    if fromm != '' and fromwho == '':
                                fromwho = fromm

                    if tmpheader != '':
                                header = tmpheader

                    if not self.config.optsyslog and not self.config.optquiet:
                                sys.stderr.write(general.colorize(_("\rDownloaded: "),general.YELLOW))
                                sys.stderr.write(general.colorize("100%\n",general.WHITE))


                    # If self.config.optexpression we've already looked for the IMAP
                    # DONTDELETETHISMESSAGE messages in the look_header method
                    if not self.config.optexpresion:
                        if msg['orignumber'] == 1:
                            resultWUIMAP = re_wuimap.search(msgbody)
                            resultWUIMAP2 = re_wuimap.search(header)
                            if (resultWUIMAP is not None) or (resultWUIMAP2 is not None):
                                aprint(_("Ignoring message %d: DONTDELETETHISMESSAGE type message") % (msg['orignumber']), general.RED)
                                retcode = 'wuimap'

                    if retcode == 'wuimap': must_deliver = False

                    try:
                                if retcode == 'postergate': #Message delayed
                                    animailBoxPath = self.config.homedir + '/.animail/animailDelayed'
                                    if not os.path.exists(animailBoxPath):
                                            os.mkdir(animailBoxPath, 0700)
                                    (foo,emailaddress) = rfc822.parseaddr(fromwho)
                                    tmpbox = open(animailBoxPath + '/' + emailaddress, 'a+')
                                    self.write_mbox(tmpbox, header, msgbody, fromm)
                                else:
                                    if retcode != 'wuimap': must_deliver = True
                                    if (self.config.lpostfilters != []) and (retcode != 'wuimap'):
                                        msgstr = self.create_msgstr(header,msgbody)
                                        tmpfile = open(tempfile.mktemp(), 'w+')
                                        os.chmod(tmpfile.name, 600)
                                        tmpfile.write(msgstr)

                                        for pfilter in self.config.lpostfilters:
                                            output = ''
                                            aprint(_("Executing postfilter %s on message...") % pfilter.filtername, general.YELLOW)
                                            (pretcode, output) = pfilter.filter_mail(msgstr,tmpfile.name)
                                            if pretcode == 1:
                                                must_deliver = False
                                                if not self.config.optnotlog: logAgent.append_filtered(indice_log,_("%s (Postfiltered by'%s')")%(fromm,pfilter.filtername),msg['size'])
                                                if pfilter.savepostfilteredmails != 0:
                                                    pfilter.log_filtered_mail(msgstr,fromm, output)
                                        tmpfile.close()
                                        os.unlink(tmpfile.name)
                                    if must_deliver:
                                        deliver(header, msgbody, fromm, smtp)

                                if self.optdelete and retcode != 'wuimap':
                                    aprint(_("Deleting message"), general.YELLOW)
                                    self.delmesg(msg)
                    except SMTPException, x:
                                print
                                print _("The local SMTP rejected this message so it won't be deleted from the mail server:"), str(x)
                                smtp.quit()
                                smtp.connect()
                                if not self.config.optnotlog:
                                    logAgent.incident(indice_log, str(x))
                    except socket.error, x:
                                print
                                print _("Socket error sending to the local SMTP, it won't be deleted from the mail server:"), str(x)
                                try:
                                    smtp.quit()
                                    smtp.connect()
                                except AttributeError: pass
                                if not self.config.optnotlog:
                                    logAgent.incident(indice_log, str(x))
                                continue
Example #58
0
    def _build_sg_mail(self, email):
        mail = Mail()
        from_name, from_email = rfc822.parseaddr(email.from_email)
        # Python sendgrid client should improve
        # sendgrid/helpers/mail/mail.py:164
        if not from_name:
            from_name = None
        mail.set_from(Email(from_email, from_name))
        mail.set_subject(email.subject)

        personalization = Personalization()
        for e in email.to:
            personalization.add_to(Email(e))
        for e in email.cc:
            personalization.add_cc(Email(e))
        for e in email.bcc:
            personalization.add_bcc(Email(e))
        personalization.set_subject(email.subject)
        mail.add_content(Content("text/plain", email.body))
        if isinstance(email, EmailMultiAlternatives):
            for alt in email.alternatives:
                if alt[1] == "text/html":
                    mail.add_content(Content(alt[1], alt[0]))
        elif email.content_subtype == "html":
            mail.contents = []
            mail.add_content(Content("text/plain", ' '))
            mail.add_content(Content("text/html", email.body))

        if hasattr(email, 'categories'):
            for c in email.categories:
                mail.add_category(Category(c))

        if hasattr(email, 'template_id'):
            mail.set_template_id(email.template_id)
            if hasattr(email, 'substitutions'):
                for key, value in email.substitutions.items():
                    personalization.add_substitution(Substitution(key, value))

        # SendGrid does not support adding Reply-To as an extra
        # header, so it needs to be manually removed if it exists.
        reply_to_string = ""
        for key, value in email.extra_headers.items():
            if key.lower() == "reply-to":
                reply_to_string = value
            else:
                mail.add_header({key: value})
        # Note that if you set a "Reply-To" header *and* the reply_to
        # attribute, the header's value will be used.
        if not mail.reply_to and hasattr(email, "reply_to") and email.reply_to:
            # SendGrid only supports setting Reply-To to a single address.
            # See https://github.com/sendgrid/sendgrid-csharp/issues/339.
            reply_to_string = email.reply_to[0]
        # Determine whether reply_to contains a name and email address, or
        # just an email address.
        if reply_to_string:
            reply_to_name, reply_to_email = rfc822.parseaddr(reply_to_string)
            if reply_to_name and reply_to_email:
                mail.set_reply_to(Email(reply_to_email, reply_to_name))
            elif reply_to_email:
                mail.set_reply_to(Email(reply_to_email))

        for attachment in email.attachments:
            if isinstance(attachment, MIMEBase):
                attach = Attachment()
                attach.set_filename(attachment.get_filename())
                attach.set_content(base64.b64encode(attachment.get_payload()))
                mail.add_attachment(attach)
            elif isinstance(attachment, tuple):
                attach = Attachment()
                attach.set_filename(attachment[0])
                base64_attachment = base64.b64encode(attachment[1])
                if sys.version_info >= (3, ):
                    attach.set_content(str(base64_attachment, 'utf-8'))
                else:
                    attach.set_content(base64_attachment)
                attach.set_type(attachment[2])
                mail.add_attachment(attach)

        mail.add_personalization(personalization)
        return mail.get()
Example #59
0
 def visit_docinfo_item(self, node, name):
     if name == "author":
         (ename, email) = rfc822.parseaddr(node.astext())
         self.docinfo["moduleauthor"] = ename
         self.docinfo["moduleauthoremail"] = email
         raise nodes.SkipNode
Example #60
0
def send_report(body,
                attachments,
                mua,
                fromaddr,
                sendto,
                ccaddr,
                bccaddr,
                headers,
                package='x',
                charset="us-ascii",
                mailing=True,
                sysinfo=None,
                rtype='debbugs',
                exinfo=None,
                replyto=None,
                printonly=False,
                template=False,
                outfile=None,
                mta='',
                kudos=False,
                smtptls=False,
                smtphost='localhost',
                smtpuser=None,
                smtppasswd=None,
                paranoid=False,
                draftpath=None,
                envelopefrom=None):
    '''Send a report.'''

    failed = using_sendmail = False
    msgname = ''
    # Disable smtphost if mua is set
    if mua and smtphost:
        smtphost = ''

    # No, I'm not going to do a full MX lookup on every address... get a
    # real MTA!
    if kudos and smtphost == 'reportbug.debian.org':
        smtphost = 'packages.debian.org'

    body_charset = charset
    if isinstance(body, unicode):
        # Since the body is Unicode, utf-8 seems like a sensible body encoding
        # to choose pretty much all the time.
        body = body.encode('utf-8', 'replace')
        body_charset = 'utf-8'

    tfprefix = tempfile_prefix(package)
    if attachments and not mua:
        (message, failed) = mime_attach(body, attachments, charset,
                                        body_charset)
        if failed:
            ewrite("Error: Message creation failed, not sending\n")
            mua = mta = smtphost = None
    else:
        message = BetterMIMEText(body, _charset=body_charset)

    # Standard headers
    message['From'] = rfc2047_encode_address(fromaddr, 'utf-8', mua)
    message['To'] = rfc2047_encode_address(sendto, charset, mua)

    for (header, value) in headers:
        if header in [
                'From', 'To', 'Cc', 'Bcc', 'X-Debbugs-CC', 'Reply-To',
                'Mail-Followup-To'
        ]:
            message[header] = rfc2047_encode_address(value, charset, mua)
        else:
            message[header] = rfc2047_encode_header(value, charset, mua)

    if ccaddr:
        message['Cc'] = rfc2047_encode_address(ccaddr, charset, mua)

    if bccaddr:
        message['Bcc'] = rfc2047_encode_address(bccaddr, charset, mua)

    replyto = os.environ.get("REPLYTO", replyto)
    if replyto:
        message['Reply-To'] = rfc2047_encode_address(replyto, charset, mua)

    if mailing:
        message['Message-ID'] = email.Utils.make_msgid('reportbug')
        message['X-Mailer'] = VERSION
        message['Date'] = email.Utils.formatdate(localtime=True)
    elif mua and not (printonly or template):
        message['X-Reportbug-Version'] = VERSION_NUMBER

    addrs = [
        str(x)
        for x in (message.get_all('To', []) + message.get_all('Cc', []) +
                  message.get_all('Bcc', []))
    ]
    alist = email.Utils.getaddresses(addrs)

    cclist = [str(x) for x in message.get_all('X-Debbugs-Cc', [])]
    debbugs_cc = email.Utils.getaddresses(cclist)
    if cclist:
        del message['X-Debbugs-Cc']
        addrlist = ', '.join(cclist)
        message['X-Debbugs-Cc'] = rfc2047_encode_address(
            addrlist, charset, mua)

    # Drop any Bcc headers from the message to be sent
    if not outfile and not mua:
        try:
            del message['Bcc']
        except:
            pass

    message = message.as_string()
    if paranoid and not (template or printonly):
        pager = os.environ.get('PAGER', 'sensible-pager')
        os.popen(pager, 'w').write(message)
        if not ui.yes_no('Does your report seem satisfactory', 'Yes, send it.',
                         'No, don\'t send it.'):
            smtphost = mta = None

    filename = None
    if template or printonly:
        pipe = sys.stdout
    elif mua:
        pipe, filename = TempFile(prefix=tfprefix, dir=draftpath)
    elif outfile or not ((mta and os.path.exists(mta)) or smtphost):
        msgname = outfile or ('/var/tmp/%s.bug' % package)
        if os.path.exists(msgname):
            try:
                os.rename(msgname, msgname + '~')
            except OSError:
                ewrite('Unable to rename existing %s as %s~\n', msgname,
                       msgname)
        try:
            pipe = open_write_safe(msgname, 'w')
        except OSError:
            # we can't write to the selected file, use a temp file instead
            fh, newmsgname = TempFile(prefix=tfprefix, dir=draftpath)
            ewrite('Writing to %s failed; '
                   'using instead %s\n', msgname, newmsgname)
            msgname = newmsgname
            # we just need a place where to write() and a file handler
            # is here just for that
            pipe = fh
    elif mta and not smtphost:
        try:
            x = os.getcwd()
        except OSError:
            os.chdir('/')

        malist = [commands.mkarg(a[1]) for a in alist]
        jalist = ' '.join(malist)

        faddr = rfc822.parseaddr(fromaddr)[1]
        if envelopefrom:
            envfrom = rfc822.parseaddr(envelopefrom)[1]
        else:
            envfrom = faddr
        ewrite("Sending message via %s...\n", mta)
        pipe = os.popen(
            '%s -f %s -oi -oem %s' % (mta, commands.mkarg(envfrom), jalist),
            'w')
        using_sendmail = True

    if smtphost:
        toaddrs = [x[1] for x in alist]
        smtp_message = re.sub(r'(?m)^[.]', '..', message)

        tryagain = True
        refused = None
        retry = 0
        while tryagain:
            tryagain = False
            ewrite("Connecting to %s via SMTP...\n", smtphost)
            try:
                conn = None
                # if we're using reportbug.debian.org, send mail to
                # submit
                if smtphost.lower() == 'reportbug.debian.org':
                    conn = smtplib.SMTP(smtphost, 587)
                else:
                    conn = smtplib.SMTP(smtphost)
                response = conn.ehlo()
                if not (200 <= response[0] <= 299):
                    conn.helo()
                if smtptls:
                    conn.starttls()
                    response = conn.ehlo()
                    if not (200 <= response[0] <= 299):
                        conn.helo()
                if smtpuser:
                    if not smtppasswd:
                        smtppasswd = ui.get_password(
                            'Enter SMTP password for %s@%s: ' %
                            (smtpuser, smtphost))
                    conn.login(smtpuser, smtppasswd)
                refused = conn.sendmail(fromaddr, toaddrs, smtp_message)
                conn.quit()
            except (socket.error, smtplib.SMTPException), x:
                # If wrong password, try again...
                if isinstance(x, smtplib.SMTPAuthenticationError):
                    ewrite('SMTP error: authentication failed.  Try again.\n')
                    tryagain = True
                    smtppasswd = None
                    retry += 1
                    if retry <= 2:
                        continue
                    else:
                        tryagain = False

                # In case of failure, ask to retry or to save & exit
                if ui.yes_no(
                        'SMTP send failure: %s. Do you want to retry (or else save the report and exit)?'
                        % x, 'Yes, please retry.', 'No, save and exit.'):
                    tryagain = True
                    continue
                else:
                    failed = True

                    fh, msgname = TempFile(prefix=tfprefix, dir=draftpath)
                    fh.write(message)
                    fh.close()

                    ewrite('Wrote bug report to %s\n', msgname)
        # Handle when some recipients are refused.
        if refused:
            for (addr, err) in refused.iteritems():
                ewrite('Unable to send report to %s: %d %s\n', addr, err[0],
                       err[1])
            fh, msgname = TempFile(prefix=tfprefix, dir=draftpath)
            fh.write(message)
            fh.close()

            ewrite('Wrote bug report to %s\n', msgname)