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', '*****@*****.**'))
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)
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'
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
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
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)
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)
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 )
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
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)
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
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
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()}
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
def to_addresses(self): addresses = [] for address in self.to_header.split(','): addresses.append( rfc822.parseaddr( address )[1] ) return addresses
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)
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]
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)
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()
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"
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)
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
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
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()
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
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
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
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()
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
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)
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
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)
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
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
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)
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
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)
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)
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
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
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
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'])
def get_mailbox_for_message(self, message): email_address = rfc822.parseaddr(message['to'])[1][0:255] return self.get_mailbox_by_name(email_address)
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
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(
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()
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() #********************************************************************************
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
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("&", "&") who = who.replace("<", "<") who = who.replace(">", ">") 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("<", "<") u_who = u_who.replace(">", ">") who = "%s<br><small><em>Uploader:</em> %s</small>" \ % (who, u_who) else: who = " " 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(\" \")\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)
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", ""))
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
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()
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
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)