def _plain_send_mail(sender, recipient, subject, body): header_charset = 'ISO-8859-1' for body_charset in 'US-ASCII', 'ISO-8859-1', 'UTF-8': try: body.encode(body_charset) except UnicodeError: pass else: break sender_name, sender_addr = parseaddr(sender) recipient_name, recipient_addr = parseaddr(recipient) sender_name = str(Header(unicode(sender_name), header_charset)) recipient_name = str(Header(unicode(recipient_name), header_charset)) sender_addr = sender_addr.encode('ascii') recipient_addr = recipient_addr.encode('ascii') msg = MIMEText(body.encode(body_charset), 'plain', body_charset) msg['From'] = formataddr((sender_name, sender_addr)) msg['To'] = formataddr((recipient_name, recipient_addr)) msg['Subject'] = Header(unicode(subject), header_charset) smtp = SMTP(config.get('registration.smtp_host', 'localhost')) if config.get('registration.smtp_login'): try: smtp.starttls() except: pass smtp.login(config.get('registration.smtp_login'), config.get('registration.smtp_passwd')) smtp.sendmail(sender, recipient, msg.as_string()) smtp.quit()
def handle_new_email_requests(self, num, raw_email): attmts = list() tmp_dict = dict() tmp_dict.update({'has_link': 'not set', 'link': None, 'object': None, 'search_link': "https://fsinvestments.my.salesforce.com"}) tmp_dict['name'], tmp_dict['email'] = parseaddr(raw_email['From'])[0], parseaddr(raw_email['From'])[1] tmp_dict['sub'] = raw_email['subject'] try: tmp_dict['date'] = datetime.datetime.strftime( date_parsing(raw_email['date']), '%m/%d/%Y %H:%M:%S') except ValueError: test_date = ' '.join(raw_email['date'].split(' ')[:-1]) tmp_dict['date'] = datetime.datetime.strftime( datetime.datetime.strptime(test_date, '%a, %d %b %Y %H:%M:%S %z'), '%m/%d/%Y %H:%M:%S') msg_body = "Sent by: %s\nReceived on: %s\nSubject: %s\n" % (tmp_dict['name'], tmp_dict['date'], tmp_dict['sub']) for part in raw_email.walk(): if part.get_content_type().lower() == "text/html" and tmp_dict['has_link'] == 'not set': e_body = fromstring(part.get_payload(decode=True)).text_content() e_body = e_body[e_body.find("-->") + 3:] tmp_dict['has_link'] = e_body.find(tmp_dict['search_link']) if tmp_dict['has_link'] not in ['not set', -1]: tmp_dict = determine_id_and_object_from_link(tmp=tmp_dict, email_text=e_body, log=self.log) msg_body += re.sub(r'[^\x00-\x7F]+', ' ', e_body) if part.get_content_maintype() == "mulipart": continue if part.get("Content-Disposition") is None: continue if part.get_filename() is not None: attmts.append(attachment_reader(raw=part, att=part.get_filename())) self.determine_path_and_complete_processing(num=num, dict_data=tmp_dict, att=attmts, msg_body=msg_body, sender_addr=tmp_dict['email']) attachment_reader(remove=True)
def modify_header(self, email): '''Generate the content for the :mailheader:`Reply-To` header :param email: The email message to modify. :type email: :class:`email.message.Message` :returns: Either: * The email address from the :mailheader:`From` header if the ``replyto`` property of the list-object is set to ``sender``. This is the default for announcement groups, as few group members can post to the group. * Both the email-address in the :mailheader:`From` header and the email-address of the group if the ``replyto`` property of the list-object is set to ``both``. (Yes, the :mailheader:`Reply-To` header can contain an *address-list* according to :rfc:`5322#section-3.6.2`.) * The email address for the group in all other cases. This is the default for most groups. :rtype: bytes''' authorReplyTo = parseaddr(email.get('Reply-To', email.get('From')))[1] groupReplyTo = parseaddr(self.listInfo.get_property('mailto'))[1] replyTo = replyto(self.listInfo) if replyTo == ReplyTo.author: retval = authorReplyTo elif replyTo == ReplyTo.both: addrs = [a for a in [authorReplyTo, groupReplyTo] if a] retval = ', '.join(addrs) else: # ReplyTo.group retval = groupReplyTo return retval
def convert_email_object_to_dict(email): """Converts a gmail.Email object into a dict to make it picklable""" return dict(subject=email.subject, fr=parseaddr(email.fr), to=parseaddr(email.to), sent_at=email.sent_at, )
def send_html_email(self, to_, from_=None, subject=None, text=None, html=None, charset="utf-8"): message = MIMEMultipart("alternative") if subject: subject_header = Header() subject = (codecs.decode(bytearray(subject, sys.getdefaultencoding()), charset) if isinstance(subject, str) else subject) subject_header.append(subject.strip()) message["Subject"] = subject_header from_ = from_ or self.default_sender from_ = (codecs.decode(bytearray(from_, sys.getdefaultencoding()), charset) if isinstance(from_, str) else from_) from_realname, from_addr = parseaddr(from_) from_header = Header() from_header.append(formataddr((from_realname, from_addr))) message['From'] = from_header to_ = (codecs.decode(bytearray(to_, sys.getdefaultencoding()), charset) if isinstance(to_, str) else to_) to_realname, to_addr = parseaddr(to_) to_header = Header() to_header.append(formataddr((to_realname, to_addr))) message['To'] = to_header message.attach(MIMEText(text, "plain", charset)) message.attach(MIMEText(html, "html", charset)) self._send(message, from_addr, to_addr)
def get_cc(doc, recipients=None, fetched_from_email_account=False): """Build a list of email addresses for CC""" # get a copy of CC list cc = split_emails(doc.cc) if doc.reference_doctype and doc.reference_name: if fetched_from_email_account: # if it is a fetched email, add follows to CC cc.append(get_owner_email(doc)) cc += get_assignees(doc) if getattr(doc, "send_me_a_copy", False) and doc.sender not in cc: cc.append(doc.sender) if cc: # exclude email accounts, unfollows, recipients and unsubscribes exclude = [d[0] for d in frappe.db.get_all("Email Account", ["email_id"], {"enable_incoming": 1}, as_list=True)] exclude += [d[0] for d in frappe.db.get_all("Email Account", ["login_id"], {"enable_incoming": 1}, as_list=True) if d[0]] exclude += [d[0] for d in frappe.db.get_all("User", ["name"], {"thread_notify": 0}, as_list=True)] exclude += [(parseaddr(email)[1] or "").lower() for email in recipients] if fetched_from_email_account: # exclude sender when pulling email exclude += [parseaddr(doc.sender)[1]] if doc.reference_doctype and doc.reference_name: exclude += [d[0] for d in frappe.db.get_all("Email Unsubscribe", ["email"], {"reference_doctype": doc.reference_doctype, "reference_name": doc.reference_name}, as_list=True)] cc = filter_email_list(doc, cc, exclude, is_cc=True) return cc
def __init__(self, name_or_email, email=None, encoding='utf-8'): if email is None: if isinstance(name_or_email, AddressList): if not 0 < len(name_or_email) < 2: raise ValueError("AddressList to convert must only contain a single Address.") name_or_email = unicode(name_or_email[0]) if isinstance(name_or_email, (tuple, list)): self.name = unicodestr(name_or_email[0], encoding) self.address = unicodestr(name_or_email[1], encoding) elif isinstance(name_or_email, bytes): self.name, self.address = parseaddr(unicodestr(name_or_email, encoding)) elif isinstance(name_or_email, unicode): self.name, self.address = parseaddr(name_or_email) else: raise TypeError('Expected string, tuple or list, got {0} instead'.format( repr(type(name_or_email)) )) else: self.name = unicodestr(name_or_email, encoding) self.address = unicodestr(email, encoding) email, err = EmailValidator().validate_email(self.address) if err: raise ValueError('"{0}" is not a valid e-mail address: {1}'.format(email, err))
def __init__(self, raw_email): metadata = raw_email[0].replace('(', '').split() # X-GM-MSGID as _id self['_created'] = datetime.now() self['X-GM-THRID'] = int(metadata[2]) self['X-GM-MSGID'] = int(metadata[4]) self['UID'] = int(metadata[6]) msg = email.message_from_string(raw_email[1]) self['Message-ID'] = msg.get('Message-ID') if msg.has_key('In-Reply-To'): self['In-Reply-To'] = msg.get_all('In-Reply-To') if msg.has_key('References'): self['References'] = msg.get('References').split('\r\n ') if msg.has_key('List-ID'): self['List-ID'] = msg.get('List-ID') self['From'] = utils.parseaddr(msg.get('From'))[1] if msg.has_key('To'): self['To'] = map(lambda x: utils.parseaddr(x)[1], msg.get_all('To')) if msg.has_key('Cc'): self['Cc'] = map(lambda x: utils.parseaddr(x)[1], msg.get_all('Cc')) self['Date'] = self._convert_string_to_date(msg.get('Date')) self['Subject'] = self._decode_text(msg.get('Subject'), msg) self['Body'] = self._get_body_from_email(msg)
def incoming_email(request, file_key): logging.info('processing incoming email %s'%file_key) data = get_blob_data(file_key) if data is None: raise Http404 logging.info('email fetch ok') email = EmailMessage(data) a_to = parseaddr(email.to)[1] a_from = parseaddr(email.sender)[1] logging.info('email.to=%s'%a_to) logging.info('email.sender=%s'%a_from) if re.match(r'^import-order@',a_to): logging.info('import order') process_incoming_email_order(email) return HttpResponse("ok - import order") if a_from == '*****@*****.**': logging.info('import order') process_incoming_email_order(email) return HttpResponse("ok - import order") r = re.match(r'^import-email-(\d+)@',a_to) if r: logging.info('import email, id %s'%r.group(1)) process_incoming_email_template(r.group(1),data) return HttpResponse("ok - import email") return HttpResponse("ok -ign")
def test_to_message_from_message_with_spam(): mb = mailbox.mbox("tests/spam") fails = 0 total = 0 for msg in mb: try: m = encoding.from_message(msg) out = encoding.to_message(m) assert repr(out) m2 = encoding.from_message(out) for k in m: if '@' in m[k]: assert_equal(parseaddr(m[k]), parseaddr(m2[k])) else: assert m[k].strip() == m2[k].strip(), "%s: %r != %r" % (k, m[k], m2[k]) assert not m[k].startswith(u"=?") assert not m2[k].startswith(u"=?") assert m.body == m2.body, "Bodies don't match" assert_equal(len(m.parts), len(m2.parts), "Not the same number of parts.") for i, part in enumerate(m.parts): assert part.body == m2.parts[i].body, "Part %d isn't the same: %r \nvs\n. %r" % (i, part.body, m2.parts[i].body) total += 1 except encoding.EncodingError, exc: fails += 1
def send_single_email(sender, recipient, subject, text, html=None, category=None): sender_name, sender_addr = parseaddr(sender) from_addr = formataddr((Header(sender_name, CHARSET_UTF8).encode(), sender_addr)) recipient_name, recipient_addr = parseaddr(recipient) to_addr = formataddr((Header(recipient_name, CHARSET_UTF8).encode(), recipient_addr)) msg = MIMEMultipart('alternative') msg['From'] = from_addr msg['To'] = to_addr msg['Subject'] = subject if category: msg["X-SMTPAPI"] = '{"category" : "%s"}' % category part1 = MIMEText(text, 'plain', CHARSET_UTF8) msg.attach(part1) if html: part2 = MIMEText(html, 'html', CHARSET_UTF8) msg.attach(part2) cfg = config() username = cfg.get('email', 'username') password = cfg.get('email', 'password') log.info('Sending email to recipient: {}'.format(recipient)) s = smtplib.SMTP(cfg.get('email', 'sp_address'), port=cfg.get('email', 'sp_port')) s.login(username, password) s.sendmail(from_addr, to_addr, msg.as_string()) s.quit()
def send_messages(self, email_messages, **kwargs): ''' Django Email Backend API - send_messages :param email_messages: list of django.core.mail.messages.EmailMessage instance - https://github.com/django /django/blob/master/django/core/mail/message.py .. todo:: - DO ERROR CHECK!!!! - DO ERROR TRACE!!!! ''' logger.debug(_('JournalEmailBackend is used to send a message.')) from tasks import journalize try: sender = parseaddr(email_messages[0].from_email)[1] recipient = parseaddr(email_messages[0].to[0])[1] journalize(sender, recipient, email_messages[0].message().as_string(), True) return 1 except Exception: for err in traceback.format_exc().split('\n'): logger.error(err) return 0
def test_gzip_attachment(): clear_queue() # set up list and message name, address = parseaddr(gzip_msg['from']) client = RouterConversation(address, 'Files Tests') client.begin() mlist = mailinglist.find_list(list_name) test_subscribe_user(sender=address, client=client, mlist=mlist) test_subscribe_user(sender=parseaddr(sender)[1], client=sender_client, mlist=mlist) gzip_msg['to'] = list_addr # deliver the message. clear_queue() Router.deliver(gzip_msg) assert len(mlist.message_set.all()) == 1 msg = mlist.message_set.all()[0] assert len(msg.file_set.all()) == 1 attached = msg.file_set.all()[0] path = os.path.join(attached.pathprefix, attached.sha) assert attached.name in os.listdir(path) assert queue().count() == 1, "Should be 1 message in queue, but there are %s" % queue().count()
def from_email(self, emails): for addr in emails: addr = parseaddr(addr)[1].lower() for my in self.from_emails: if parseaddr(my)[1].lower() == addr: return my return None
def send_email(self, to_, from_=None, subject=None, body=None, subtype="plain", charset="utf-8"): message = MIMEText(body, subtype, charset) if subject: subject_header = Header() subject = (codecs.decode(bytearray(subject, sys.getdefaultencoding()), charset) if isinstance(subject, str) else subject) subject_header.append(subject.strip()) message["Subject"] = subject_header from_ = from_ or self.default_sender from_ = (codecs.decode(bytearray(from_, sys.getdefaultencoding()), charset) if isinstance(from_, str) else from_) from_realname, from_addr = parseaddr(from_) from_header = Header() from_header.append(formataddr((from_realname, from_addr))) message['From'] = from_header to_ = (codecs.decode(bytearray(to_, sys.getdefaultencoding()), charset) if isinstance(to_, str) else to_) to_realname, to_addr = parseaddr(to_) to_header = Header() to_header.append(formataddr((to_realname, to_addr))) message['To'] = to_header self._send(message, from_addr, to_addr)
def get_recipients(self, except_recipient=False): """Build a list of users to which this email should go to""" original_recipients = [s.strip() for s in self.recipients.split(",")] recipients = original_recipients[:] if self.reference_doctype and self.reference_name: recipients += self.get_earlier_participants() recipients += self.get_commentors() recipients += self.get_assignees() recipients += self.get_starrers() # remove unsubscribed recipients unsubscribed = [d[0] for d in frappe.db.get_all("User", ["name"], {"thread_notify": 0}, as_list=True)] email_accounts = [d[0] for d in frappe.db.get_all("Email Account", ["email_id"], {"enable_incoming": 1}, as_list=True)] sender = parseaddr(self.sender)[1] filtered = [] for e in list(set(recipients)): if (e=="Administrator") or ((e==self.sender) and (e not in original_recipients)) or \ (e in unsubscribed) or (e in email_accounts): continue email_id = parseaddr(e)[1] if email_id==sender or email_id in unsubscribed or email_id in email_accounts: continue if except_recipient and (e==self.recipients or email_id==self.recipients): # while pulling email, don't send email to current recipient continue if e not in filtered and email_id not in filtered: filtered.append(e) return filtered
def post(self, request): token = request.POST['token'] signature = request.POST['signature'] timestamp = request.POST['timestamp'] key = options.get('mail.mailgun-api-key') if not key: logging.error('mail.mailgun-api-key is not set') return HttpResponse(status=500) if not self.verify(key, token, timestamp, signature): logging.info('Unable to verify signature for mailgun request') return HttpResponse(status=403) to_email = parseaddr(request.POST['To'])[1] from_email = parseaddr(request.POST['From'])[1] try: group_id = email_to_group_id(to_email) except Exception: logging.info('%r is not a valid email address', to_email) return HttpResponse(status=500) payload = EmailReplyParser.parse_reply(request.POST['body-plain']).strip() if not payload: # If there's no body, we don't need to go any further return HttpResponse(status=200) process_inbound_email.delay(from_email, group_id, payload) return HttpResponse(status=201)
def create_mail_document(self,mail): body = "" if(mail.is_multipart()): body = self.get_body_from_multipart_mail(mail) else: body = unicode(mail.get_payload(decode=True),self.get_charset(mail),"replace") from_email = parseaddr(mail.get('From'))[1] if(mail.get_all('Cc')): ccs_string = mail.get_all('Cc') else: ccs_string = '' if(mail.get_all('To')): tos_string = mail.get_all('To') else: tos_string = '' cc_emails = map(lambda addr:addr[1],getaddresses(ccs_string)) to_emails = map(lambda addr:addr[1],getaddresses(tos_string)) from_user = parseaddr(mail.get('From'))[0] subject = mail.get('Subject') message_id = mail.get('Message-Id') date = datetime.fromtimestamp(mktime(parsedate(mail.get('Date')))) body = Mail.clean_body(body) from_user = self.get_user_name(from_user,from_email) sender ,creation_status = User.objects.get_or_create(email=from_email,auto_save=False) if creation_status: sender.name = from_user sender.save() mail_document = Mail(message_id=message_id,body=body,to=to_emails,sender=sender,cc=cc_emails,subject=subject,date=date) return mail_document
def send(debug, header, To, Content, filenames=None): header['From'] = formataddr(parseaddr(header['From'])) To = formataddr(parseaddr(To)) if filenames: msg = multipart.MIMEMultipart() # a header mezőit átmásoljuk az üzenetbe for field in header: msg[field] = header[field] msg['To'] = To body = text.MIMEText(Content, 'plain', 'utf-8') msg.attach(body) for filename in filenames: msg.attach(attach(filename)) # Csatolás nélküli szimpla email else: msg = text.MIMEText(Content, 'plain', 'utf-8') for field in header: msg[field] = header[field] msg['To'] = To # Ha csak debug kell, akkor elmentjük a "debug" változóba if debug: open(debug, 'a').write('From pistike Mon Jan 01 00:00:00 2000\n' + msg.as_string() + '\n') # egyébként elküldjük else: s = smtplib.SMTP('localhost') s.sendmail(header['From'], [To], msg.as_string()) s.quit()
def _build_standard_message_dict(self, message): """Create a Mandrill send message struct from a Django EmailMessage. Builds the standard dict that Django's send_mail and send_mass_mail use by default. Standard text email messages sent through Django will still work through Mandrill. Raises ValueError for any standard EmailMessage features that cannot be accurately communicated to Mandrill (e.g., prohibited headers). """ sender = sanitize_address(message.from_email, message.encoding) from_name, from_email = parseaddr(sender) recipients = [parseaddr(sanitize_address(addr, message.encoding)) for addr in message.recipients()] to_list = [{"email": to_email, "name": to_name} for (to_name, to_email) in recipients] msg_dict = { "text": message.body, "subject": message.subject, "from_email": from_email, "to": to_list } if from_name: msg_dict["from_name"] = from_name if message.extra_headers: for k in message.extra_headers.keys(): if k != "Reply-To" and not k.startswith("X-"): raise ValueError("Invalid message header '%s' - Mandrill " "only allows Reply-To and X-* headers" % k) msg_dict["headers"] = message.extra_headers return msg_dict
def generate_name(msg, folder_path): mailtm = msg.get('Date') messageid = msg.get('Message-Id') subject = msg.get('Subject') from_email = msg.get('From') path = [folder_path] flag = 0 flag = check_from_subject(from_email, subject) #检查邮件的类型:0 正常,1 错误,2 垃圾 if flag: #根据邮件的类型,来分开存放 path.append(mailtype[flag]) mailtime = time.localtime(handle_time(mailtm)) m = hashlib.md5() m.update(msg.get('message-id', 'none')) m.update(msg.get('From', 'none')) m.update(msg.get('Subject', 'None')) inbox_time = time.strftime('%Y-%m-%d %H:%M:%S', mailtime) if '@' in utils.parseaddr(msg.get('From'))[1]: fle_name = time.strftime("%d-%H%M%S-",mailtime) + m.hexdigest()+"-"+ utils.parseaddr(msg.get('From'))[1]+".eml" else: fle_name = time.strftime("%d-%H%M%S-",mailtime) + m.hexdigest()+".eml" folder = time.strftime('%Y%m', mailtime) path.append(folder) if not os.path.exists('/'.join(path)): os.makedirs('/'.join(path)) path.append(fle_name) return (flag, inbox_time, '/'.join(path), m.hexdigest())
def testEmailParsing(self): # create an initial "from" email message = email.message_from_file( open("./testdata/mail3.txt", "r")) name, mto = parseaddr(message['to']) name, mfrom = parseaddr(message['from']) for part in message.walk(): if part.get_content_maintype() == "multipart": continue # it's just a container if part.get_content_type() == "text/plain": body = part.get_payload(decode=True) break try: user = CustomUser.objects.get( email=mfrom) except CustomUser.DoesNotExist: user = CustomUser.objects.create(email=mfrom, username=mfrom) user.set_unusable_password() user.save() recipient, _ = CustomUser.objects.get_or_create( email=mto, username=mto) mail = Mail.objects.create( subject=message['subject'], mfrom=user, mto=recipient, message=body) # now we simulate a reply, and override a couple of relevant # headers raw_email = email.message_from_file( open("./testdata/mail4.txt", "r")) new_mto = user.proxy_email raw_email.replace_header('in-reply-to', "<%s>" % mail.message_id) raw_email.replace_header('references', "<%s>" % mail.message_id) raw_email.replace_header('to', "%s <%s>" % (mail.message_id, new_mto)) fp = StringIO(raw_email.as_string()) response = make_response_from_file(fp) self.assertTrue(response) # now parse in an email that isn't a response to anything fp = open("./testdata/mail2.txt", "r") response = make_response_from_file(fp) self.assertEqual(response, EX_NOUSER) # and now try threading based on subject line as a fallback... raw_email = email.message_from_file( open("./testdata/mail2.txt", "r")) new_mto = user.proxy_email del(raw_email['in-reply-to']) del(raw_email['references']) raw_email.replace_header('subject', "Re:RE: re:%s" % mail.subject) raw_email.replace_header('to', "%s <%s>" % (mail.message_id, new_mto)) fp = StringIO(raw_email.as_string()) response = make_response_from_file(fp) self.assertTrue(response)
def send_email(self, sender, recipient, subject, body): """ Send an email :param sender: the senders address :param recipient: the recipients address :param subject: the emails subject :param body: the body of the email :return: nothing """ # Header class is smart enough to try US-ASCII, then the charset we # provide, then fall back to UTF-8. header_charset = 'ISO-8859-1' # We must choose the body charset manually body_charset = None for body_charset in 'US-ASCII', 'ISO-8859-1', 'UTF-8': try: body.encode(body_charset) except UnicodeError: pass else: break if body_charset is None: log.error("Can not encode body of an email") raise Exception("Email body encoding problem for email with subject{}".format(subject)) # Split real name (which is optional) and email address parts sender_name, sender_addr = parseaddr(sender) recipient_name, recipient_addr = parseaddr(recipient) # We must always pass Unicode strings to Header, otherwise it will # use RFC 2047 encoding even on plain ASCII strings. sender_name = str(Header(unicode(sender_name), header_charset)) recipient_name = str(Header(unicode(recipient_name), header_charset)) # Make sure email addresses do not contain non-ASCII characters sender_addr = sender_addr.encode('ascii') recipient_addr = recipient_addr.encode('ascii') # Create the message ('plain' stands for Content-Type: text/plain) msg = MIMEText(body.encode(body_charset), 'plain', body_charset) msg['From'] = formataddr((sender_name, sender_addr)) msg['To'] = formataddr((recipient_name, recipient_addr)) msg['Subject'] = Header(unicode(subject), header_charset) try: # Send the message via SMTP to localhost:25 smtp = SMTP(self._config['email.smtp_server'], port=self._config['email.smtp_port'], timeout=1) smtp.sendmail(sender, recipient, msg.as_string()) smtp.quit() except KeyError: log.warn("There is no smtp server set in the config file.") except timeout: log.error("There is smtp timeout error message not sent.") log.error("Message was %s" % str(msg)) except SMTPException, ex: log.error("There is smtp error. Message not sent: %s." % str(ex)) log.error("Message was %s" % str(msg))
def parse(content): p = EmailParser() msgobj = p.parsestr(content) if msgobj['Subject'] is not None: decodefrag = decode_header(msgobj['Subject']) subj_fragments = [] for s, enc in decodefrag: if enc: s = unicode(s , enc).encode('utf8', 'replace') subj_fragments.append(s) subject = ''.join(subj_fragments) else: subject = None attachments = [] body = None html = None images = [] images_content_type = [ "image/jpg", "image/jpeg", "image/png", "image/tiff" "application/pdf", ] for part in msgobj.walk(): print part.get_content_type() attachment = parse_attachment(part) if attachment: attachments.append(attachment) elif part.get_content_type() == "text/plain": if body is None: body = "" body += unicode( part.get_payload(decode=True), part.get_content_charset(), 'replace' ).encode('utf8', 'replace') elif part.get_content_type() == "text/html": if html is None: html = "" html += unicode( part.get_payload(decode=True), part.get_content_charset(), 'replace' ).encode('utf8', 'replace') elif part.get_content_type() in images_content_type: images.append(StringIO(part.get_payload(decode=True))) return { 'subject': subject, 'body': body, 'html': html, 'from': parseaddr(msgobj.get('From'))[1], 'to': parseaddr(msgobj.get('To'))[1], 'attachments': attachments, 'images': images, }
def parse(content): #p = EmailParser() #msgobj = p.parse(content) msgobj = content messagedate = parser.parse(msgobj['Date']) if msgobj['Subject'] is not None: decodefrag = decode_header(msgobj['Subject']) subj_fragments = [] for s , enc in decodefrag: if enc: try: s = unicode(s , enc).encode('utf8','replace') except: print "CANNOT DECODE" subj_fragments.append(s) subject = ''.join(subj_fragments) else: subject = None attachments = [] body = None html = None for part in msgobj.walk(): attachment = None#parse_attachment(part) if attachment: attachments.append(attachment) elif part.get_content_type() == "text/plain": try: if body is None: body = "" body += unicode( part.get_payload(decode=True), "Latin-1" if part.get_content_charset() is None else part.get_content_charset(), 'replace' ).encode('utf8','replace') except: print "CANNOT DECODE" elif part.get_content_type() == "text/html": try: if html is None: html = "" html += unicode( part.get_payload(decode=True), "Latin-1" if part.get_content_charset() is None else part.get_content_charset(), 'replace' ).encode('utf8','replace') except: print "CANNOT DECODE" return { 'date' : messagedate, 'subject' : subject, 'body' : body, 'html' : html, 'from' : parseaddr(msgobj.get('From'))[1], 'to' : parseaddr(msgobj.get('To'))[1], 'attachments': attachments, }
def fetch_and_store(): detach_dir = '.' m = imaplib.IMAP4_SSL("imap.gmail.com") m.login('*****@*****.**',getPassword()) m.select("inbox") resp, items = m.search(None, "(UNSEEN)") items = items[0].split() for emailid in items: resp, data = m.fetch(emailid, "(RFC822)") email_body = data[0][1] resp2, header = m.fetch(emailid, '(BODY[HEADER.FIELDS (SUBJECT)])') subject = header[0][1] parser = HeaderParser() msg = parser.parsestr(subject) subjectline = "".join(re.findall(r'[0-9a-zA-Z\-]', msg["Subject"])) mail = email.message_from_string(email_body) from email.utils import parseaddr fromaddr = parseaddr(mail['from'])[1] name = parseaddr(mail['from'])[0] temp = m.store(emailid,'+FLAGS', '\\Seen') m.expunge() sender = checkSender(fromaddr) if not parseSubLine(subjectline) or not sender : #Ifall mailet har fel rubrik, går vi in här if not parseSubLine(subjectline) : print "Warning: Mail has wrong subject" sendEmail(name, fromaddr, subjectline, "2") #Skickar ett mail till avsändaren om att dess mail haft fel format på rubriken elif not sender : print "Warning: Address not in senders file" sendEmail(name, fromaddr, subjectline, "1") #Skickar ett mail till avsändaren om adressen inte finns i "sender.txt"-listan else: if not os.path.exists(subjectline): os.makedirs(subjectline) if mail.get_content_maintype() != 'multipart': continue filenamelist = [] for part in mail.walk(): if part.get_content_maintype() == 'multipart': continue if part.get('Content-Disposition') is None: continue filename = "".join(re.findall(r'[.0-9a-zA-Z\-]',part.get_filename())) att_path = os.path.join(detach_dir + "/" + subjectline, filename) filenamelist.append(filename) if not os.path.isfile(att_path) : fp = open(att_path, 'wb') fp.write(part.get_payload(decode=True)) fp.close() course = sender[0] name = sender[1] dest = "www/uppladdat/" + course + "/{0}.pdf".format(setFileName(sender,subjectline)) convertStoredToPdf(subjectline, dest)
def parse(content): """ parse email """ p = EmailParser() #check content is a file or text #if content is path... #msgobj = p.parse(content) msgobj = p.parsestr(content) if msgobj['Subject'] is not None: decodefrag = decode_header(msgobj['Subject']) subj_fragments = [] for s , enc in decodefrag: if enc: s = unicode(s , enc).encode('utf8','replace') subj_fragments.append(s) subject = ''.join(subj_fragments) else: subject = None attachments = [] body = None html = None for part in msgobj.walk(): attachment = parse_attachment(part) if attachment: attachments.append(attachment) elif part.get_content_type() == "text/plain": if body is None: body = "" if part.get_content_charset: body += part.get_payload(decode=True) else: body += unicode( part.get_payload(decode=True), part.get_content_charset(), 'replace' ).encode('utf8','replace') elif part.get_content_type() == "text/html": if html is None: html = "" html += unicode( part.get_payload(decode=True), part.get_content_charset(), 'replace' ).encode('utf8','replace') return { 'subject' : subject, 'body' : body, 'html' : html, 'from' : parseaddr(msgobj.get('From'))[1], 'to' : parseaddr(msgobj.get('To'))[1], 'date' : parse_date(msgobj.get('Date')), 'attachments': attachments, }
def test_set_formally_from(self): e = get_email('Faux') fh = FromHeader(FauxGroup, FauxRequest) fh.set_formally_from(e) self.assertIn('X-GS-Formerly-From', e) f = parseaddr(e['From'])[1] ff = parseaddr(e['X-GS-Formerly-From'])[1] self.assertEqual(f, ff)
def main(): parser = OptionParser(usage="""\ Unpack a MIME message into 3s. MIME message is read from standard input Usage: %prog < mime-message """) directory = tempfile.mkdtemp() phone_number_regex = re.compile(PHONE_NUMBER_EX) try: message_string = StringIO.StringIO(sys.stdin.read()) msg = email.message_from_file(message_string) message_string.seek(0) subject = msg['subject'] log.debug('processing mail with subject %s' % subject) # Try finding the "Caller-ID: <phone number>" pattern in the subject line # if found try looking for a user that has this fax # associated to the account # use that user as the owner of the incoming mail/fax m = phone_number_regex.search(subject) owner = None if m: log.debug('Found FAX number %s' % m.group()) try: fax_number = '-'.join(m.groups()) owner = UserProfile.objects.get(fax_number = fax_number).user except UserProfile.NotFound: pass else: log.debug('FAX number not found in subject') if not owner: try: log.debug('parseaddr returns %s' % str(parseaddr(msg['from']))) owner = User.objects.get(email=parseaddr(msg['from'])[1]) except Exception, e: log.warn("user with email address %s not found. ignoring message" % msg['from']) return mail_gateway = get_or_create_processor( 'docstore.gateway.mail', DEFAULT_OUTPUTS) create_doc_with_initial_view( mail_gateway, mail_gateway.outputs.get( name = 'email'), owner, subject, message_string)
def mails_urls(source_list, m_pattern, u_pattern): app_mail_list = [] app_url_list = [] for taken in source_list: taken = taken.strip('<,>') if re.match(m_pattern, parseaddr(taken)[1]): app_mail_list.append(parseaddr(taken)[1]) elif re.match(u_pattern, taken): app_url_list.append(taken) return (app_mail_list, app_url_list)
def _sns_message(message_json): incr_if_enabled('sns_inbound_Notification_Received', 1) mail = message_json['mail'] if message_json.get('eventType') == 'Bounce': return _handle_bounce(message_json) if 'commonHeaders' not in mail: logger.error('SNS message without commonHeaders') return HttpResponse('Received SNS notification without commonHeaders.', status=400) if 'to' not in mail['commonHeaders']: logger.error('SNS message without commonHeaders "to".') return HttpResponse( 'Received SNS notification without commonHeaders "to".', status=400) to_address = parseaddr(mail['commonHeaders']['to'][0])[1] local_portion = to_address.split('@')[0] if local_portion == 'noreply': incr_if_enabled('email_for_noreply_address', 1) return HttpResponse('noreply address is not supported.') domain_portion = to_address.split('@')[1] try: # FIXME: this ambiguous return of either # RelayAddress or DomainAddress types makes the Rustacean in me throw # up a bit. address = _get_address(to_address, local_portion, domain_portion) user_profile = address.user.profile_set.first() except Exception: return HttpResponse("Address does not exist", status=404) address_hash = sha256(to_address.encode('utf-8')).hexdigest() # first see if this user is over bounce limits bounce_paused, bounce_type = user_profile.check_bounce_pause() if bounce_paused: incr_if_enabled('email_suppressed_for_%s_bounce' % bounce_type, 1) return HttpResponse("Address is temporarily disabled.") if address and not address.enabled: incr_if_enabled('email_for_disabled_address', 1) address.num_blocked += 1 address.save(update_fields=['num_blocked']) return HttpResponse("Address is temporarily disabled.") incr_if_enabled('email_for_active_address', 1) logger.info('email_relay', extra={ 'fxa_uid': user_profile.fxa.uid, 'address': address_hash, 'real_address': sha256( user_profile.user.email.encode('utf-8')).hexdigest(), }) from_address = parseaddr(mail['commonHeaders']['from'])[1] subject = mail['commonHeaders'].get('subject', '') bytes_email_message = message_from_bytes( message_json['content'].encode('utf-8'), policy=policy.default) text_content, html_content, attachments = _get_all_contents( bytes_email_message) strip_texts = [] for item in mail['headers']: for k, v in item.items(): strip_texts.append(': '.join([k, v])) stripped_content = message_json['content'] for item in strip_texts: stripped_content = stripped_content.replace(item, '') # scramble alias so that clients don't recognize it # and apply default link styles display_email = re.sub('([@.:])', r'<span>\1</span>', to_address) message_body = {} if html_content: incr_if_enabled('email_with_html_content', 1) wrapped_html = render_to_string( 'emails/wrapped_email.html', { 'original_html': html_content, 'email_to': to_address, 'display_email': display_email, 'SITE_ORIGIN': settings.SITE_ORIGIN, 'has_attachment': bool(attachments), 'faq_page': settings.SITE_ORIGIN + reverse('faq'), 'survey_text': settings.RECRUITMENT_EMAIL_BANNER_TEXT, 'survey_link': settings.RECRUITMENT_EMAIL_BANNER_LINK }) message_body['Html'] = {'Charset': 'UTF-8', 'Data': wrapped_html} if text_content: incr_if_enabled('email_with_text_content', 1) attachment_msg = ( 'Firefox Relay supports email forwarding (including attachments) ' 'of email up to 150KB in size. To learn more visit {site}{faq}\n' ).format(site=settings.SITE_ORIGIN, faq=reverse('faq')) relay_header_text = ( 'This email was sent to your alias ' '{alias}. To stop receiving emails sent to this alias, ' 'update the forwarding settings in your dashboard.\n' '{extra_msg}---Begin Email---\n').format(alias=to_address, extra_msg=attachment_msg) wrapped_text = relay_header_text + text_content message_body['Text'] = {'Charset': 'UTF-8', 'Data': wrapped_text} return ses_relay_email( from_address, address, subject, message_body, attachments, user_profile.user.email, )
def formatAddress(address): return formataddr(parseaddr(address))
def receive(self, message): #如果有多个收件人的话,只解释第一个收件人 to = parseaddr(message.to)[1] to = to.split('@')[0] if to and '@' in to else 'xxx' if '__' in to: listto = to.split('__') username = listto[0] if listto[0] else 'admin' to = listto[1] else: username = '******' user = KeUser.all().filter('name = ', username).get() if not user: username = '******' user = KeUser.all().filter('name = ', username).get() if not user or not user.kindle_email: self.response.out.write('No account or no email configured!') return sender = parseaddr(message.sender)[1] mailhost = sender.split('@')[1] if sender and '@' in sender else None if (not sender or not mailhost) or \ (not user.whitelist.filter('mail = ', '*').get() and not user.whitelist.filter('mail = ', sender.lower()).get() and not user.whitelist.filter('mail = ', '@' + mailhost.lower()).get()): self.response.out.write("Spam mail!") default_log.warn('Spam mail from : %s' % sender) return if hasattr(message, 'subject'): subject = decode_subject(message.subject) else: subject = u"NoSubject" #通过邮件触发一次“现在投递” if to.lower() == 'trigger': return self.TrigDeliver(subject, username) #获取和解码邮件内容 txt_bodies = message.bodies('text/plain') html_bodies = message.bodies('text/html') try: allBodies = [body.decode() for ctype, body in html_bodies] except: default_log.warn('Decode html bodies of mail failed.') allBodies = [] #此邮件为纯文本邮件 if len(allBodies) == 0: default_log.info('no html body, use text body.') try: allBodies = [body.decode() for ctype, body in txt_bodies] except: default_log.warn('Decode text bodies of mail failed.') allBodies = [] bodies = u''.join(allBodies) if not bodies: return bodyurls = [] for l in bodies.split('\n'): l = l.strip() if not l: continue link = IsHyperLink(l) if link: bodyurls.append('<a href="%s">%s</a><br />' % (link, link)) else: break bodies = u"""<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>%s</title></head><body>%s</body></html>""" % ( subject, ''.join(bodyurls) if bodyurls else bodies) allBodies = [bodies.encode('utf-8')] #开始处理邮件内容 soup = BeautifulSoup(allBodies[0], 'lxml') #合并多个邮件文本段 if len(allBodies) > 1: for o in allBodies[1:]: so = BeautifulSoup(o, 'lxml') b = so.find('body') if not b: continue for c in b.contents: soup.body.append(c) #判断邮件内容是文本还是链接(包括多个链接的情况) links = [] body = soup.body if soup.find('body') else soup for s in body.stripped_strings: link = IsHyperLink(s) if link: links.append(link) else: #如果是多个链接,则必须一行一个 break if not links: #正常字符判断没有链接,看html的a标签 links = list(soup.find_all('a', attrs={'href': True})) link = links[0]['href'] if links else '' text = ' '.join([s for s in body.stripped_strings]) text = text.replace(link, '') #如果字数太多,则认为直接推送正文内容 if len(links) != 1 or len(text) > WORDCNT_THRESHOLD_FOR_APMAIL: links = [] if links: #判断是下载文件还是转发内容 isbook = bool(to.lower() in ('book', 'file', 'download')) isbook = link[-5:].lower() in ('.mobi', '.epub', '.docx') if not isbook else isbook isbook = link[-4:].lower() in ('.pdf', '.txt', '.doc', '.rtf') if not isbook else isbook param = { 'u': username, 'urls': '|'.join(links), 'type': 'Download' if isbook else user.book_type, 'to': user.kindle_email, 'tz': user.timezone, 'subject': subject[:SUBJECT_WORDCNT_FOR_APMAIL], 'lng': user.ownfeeds.language, 'keepimage': '1' if user.ownfeeds.keep_image else '0' } taskqueue.add(url='/url2book', queue_name="deliverqueue1", method='GET', params=param, target='worker') else: #直接转发邮件正文 #先判断是否有图片 from lib.makeoeb import MimeFromFilename hasimage = False if hasattr(message, 'attachments'): for f, c in message.attachments: if MimeFromFilename(f): hasimage = True break #先修正不规范的HTML邮件 h = soup.find('head') if not h: h = soup.new_tag('head') soup.html.insert(0, h) t = soup.head.find('title') if not t: t = soup.new_tag('title') t.string = subject soup.head.insert(0, t) #有图片的话,要生成MOBI或EPUB才行 #而且多看邮箱不支持html推送,也先转换epub再推送 if hasimage or (user.book_type == "epub"): from main import local_time from lib.makeoeb import (getOpts, CreateOeb, setMetaData, ServerContainer, byteStringIO, EPUBOutput, MOBIOutput) #仿照Amazon的转换服务器的处理,去掉CSS if DELETE_CSS_FOR_APPSPOTMAIL: tag = soup.find('style', attrs={'type': 'text/css'}) if tag: tag.extract() for tag in soup.find_all(attrs={'style': True}): del tag['style'] #将图片的src的文件名调整好 for img in soup.find_all('img', attrs={'src': True}): if img['src'].lower().startswith('cid:'): img['src'] = img['src'][4:] opts = getOpts() oeb = CreateOeb(default_log, None, opts) setMetaData(oeb, subject[:SUBJECT_WORDCNT_FOR_APMAIL], user.ownfeeds.language, local_time(tz=user.timezone), pubtype='book:book:KindleEar') oeb.container = ServerContainer(default_log) id, href = oeb.manifest.generate(id='page', href='page.html') item = oeb.manifest.add(id, href, 'application/xhtml+xml', data=unicode(soup)) oeb.spine.add(item, False) oeb.toc.add(subject, href) if hasattr(message, 'attachments'): for filename, content in message.attachments: mimetype = MimeFromFilename(filename) if mimetype: try: content = content.decode() except: pass else: id, href = oeb.manifest.generate(id='img', href=filename) item = oeb.manifest.add(id, href, mimetype, data=content) oIO = byteStringIO() o = EPUBOutput() if user.book_type == "epub" else MOBIOutput() o.convert(oeb, oIO, opts, default_log) BaseHandler.SendToKindle(username, user.kindle_email, subject[:SUBJECT_WORDCNT_FOR_APMAIL], user.book_type, str(oIO.getvalue()), user.timezone) else: #没有图片则直接推送HTML文件,阅读体验更佳 m = soup.find('meta', attrs={"http-equiv": "Content-Type"}) if not m: m = soup.new_tag('meta', content="text/html; charset=utf-8") m["http-equiv"] = "Content-Type" soup.html.head.insert(0, m) else: m['content'] = "text/html; charset=utf-8" html = unicode(soup).encode('utf-8') BaseHandler.SendToKindle(username, user.kindle_email, subject[:SUBJECT_WORDCNT_FOR_APMAIL], 'html', html, user.timezone, False) self.response.out.write('Done')
def parse_email_address(value): name, mail = parseaddr(value) return { 'name': name, 'email': mail }
def _format_addr(s): name, addr = parseaddr(s) return formataddr(( \ Header(name, 'utf-8').encode(), \ addr.encode('utf-8') if isinstance(addr, unicode) else addr))
def tokenized_no_reply_address() -> str: if settings.ADD_TOKENS_TO_NOREPLY_ADDRESS: return parseaddr( settings.TOKENIZED_NOREPLY_EMAIL_ADDRESS)[1].format( token=generate_key()) return FromAddress.NOREPLY
def parse(self, m, prefix=None): """Parse messages sent by the 'buildbot-cvs-mail' program. """ # The mail is sent from the person doing the checkin. Assume that the # local username is enough to identify them (this assumes a one-server # cvs-over-rsh environment rather than the server-dirs-shared-over-NFS # model) name, addr = parseaddr(m["from"]) if not addr: # no From means this message isn't from buildbot-cvs-mail return None at = addr.find("@") if at == -1: author = addr # might still be useful else: author = addr[:at] author = util.ascii2unicode(author) # CVS accepts RFC822 dates. buildbot-cvs-mail adds the date as # part of the mail header, so use that. # This assumes cvs is being access via ssh or pserver, so the time # will be the CVS server's time. # calculate a "revision" based on that timestamp, or the current time # if we're unable to parse the date. log.msg('Processing CVS mail') dateTuple = parsedate_tz(m["date"]) if dateTuple is None: when = util.now() else: when = mktime_tz(dateTuple) theTime = datetime.datetime.utcfromtimestamp(float(when)) rev = theTime.strftime('%Y-%m-%d %H:%M:%S') catRE = re.compile(r'^Category:\s*(\S.*)') cvsRE = re.compile(r'^CVSROOT:\s*(\S.*)') cvsmodeRE = re.compile(r'^Cvsmode:\s*(\S.*)') filesRE = re.compile(r'^Files:\s*(\S.*)') modRE = re.compile(r'^Module:\s*(\S.*)') pathRE = re.compile(r'^Path:\s*(\S.*)') projRE = re.compile(r'^Project:\s*(\S.*)') singleFileRE = re.compile(r'(.*) (NONE|\d(\.|\d)+) (NONE|\d(\.|\d)+)') tagRE = re.compile(r'^\s+Tag:\s*(\S.*)') updateRE = re.compile(r'^Update of:\s*(\S.*)') comments = "" branch = None cvsroot = None fileList = None files = [] isdir = 0 path = None project = None lines = list(body_line_iterator(m)) while lines: line = lines.pop(0) m = catRE.match(line) if m: category = m.group(1) continue m = cvsRE.match(line) if m: cvsroot = m.group(1) continue m = cvsmodeRE.match(line) if m: cvsmode = m.group(1) continue m = filesRE.match(line) if m: fileList = m.group(1) continue m = modRE.match(line) if m: # We don't actually use this # module = m.group(1) continue m = pathRE.match(line) if m: path = m.group(1) continue m = projRE.match(line) if m: project = m.group(1) continue m = tagRE.match(line) if m: branch = m.group(1) continue m = updateRE.match(line) if m: # We don't actually use this # updateof = m.group(1) continue if line == "Log Message:\n": break # CVS 1.11 lists files as: # repo/path file,old-version,new-version file2,old-version,new-version # Version 1.12 lists files as: # file1 old-version new-version file2 old-version new-version # # files consists of tuples of 'file-name old-version new-version' # The versions are either dotted-decimal version numbers, ie 1.1 # or NONE. New files are of the form 'NONE NUMBER', while removed # files are 'NUMBER NONE'. 'NONE' is a literal string # Parsing this instead of files list in 'Added File:' etc # makes it possible to handle files with embedded spaces, though # it could fail if the filename was 'bad 1.1 1.2' # For cvs version 1.11, we expect # my_module new_file.c,NONE,1.1 # my_module removed.txt,1.2,NONE # my_module modified_file.c,1.1,1.2 # While cvs version 1.12 gives us # new_file.c NONE 1.1 # removed.txt 1.2 NONE # modified_file.c 1.1,1.2 if fileList is None: log.msg('CVSMaildirSource Mail with no files. Ignoring') return None # We don't have any files. Email not from CVS if cvsmode == '1.11': # Please, no repo paths with spaces! m = re.search('([^ ]*) ', fileList) if m: path = m.group(1) else: log.msg( 'CVSMaildirSource can\'t get path from file list. Ignoring mail' ) return fileList = fileList[len(path):].strip() singleFileRE = re.compile( r'(.+?),(NONE|(?:\d+\.(?:\d+\.\d+\.)*\d+)),(NONE|(?:\d+\.(?:\d+\.\d+\.)*\d+))(?: |$)' ) elif cvsmode == '1.12': singleFileRE = re.compile( r'(.+?) (NONE|(?:\d+\.(?:\d+\.\d+\.)*\d+)) (NONE|(?:\d+\.(?:\d+\.\d+\.)*\d+))(?: |$)' ) if path is None: raise ValueError( 'CVSMaildirSource cvs 1.12 require path. Check cvs loginfo config' ) else: raise ValueError('Expected cvsmode 1.11 or 1.12. got: %s' % cvsmode) log.msg("CVSMaildirSource processing filelist: %s" % fileList) while (fileList): m = singleFileRE.match(fileList) if m: curFile = path + '/' + m.group(1) files.append(curFile) fileList = fileList[m.end():] else: log.msg('CVSMaildirSource no files matched regex. Ignoring') return None # bail - we couldn't parse the files that changed # Now get comments while lines: line = lines.pop(0) comments += line comments = comments.rstrip() + "\n" if comments == '\n': comments = None return ('cvs', dict(author=author, files=files, comments=comments, isdir=isdir, when=when, branch=branch, revision=rev, category=category, repository=cvsroot, project=project, properties=self.properties))
def main(): # Part 0. Prepare environment log = open(MFCNS_LOGFILE, 'a') logfd = log.fileno() os.dup2(logfd, STDOUT_FILENO) os.dup2(logfd, STDERR_FILENO) lprintf('MFCns_handler started') atexit.register(cleanup) # Part I. Spool dir processing mfc_rex = re.compile(MFC_PTRN) for filename in os.listdir(MFCNS_SPOOL): filename = os.path.join(MFCNS_SPOOL, filename) if not os.path.isfile(filename): lprintf('%s: not a file found in the spool directory', filename) continue lprintf('Processing "%s"...', filename) fdes = open(filename, 'r', encoding='utf-8') message = message_from_file(fdes) date = list(parsedate(message['Date'])) fdes.seek(0, 0) content = fdes.readlines() fdes.close() mfc_in = -1 for line in content: result = mfc_rex.match(line) if result == None: continue mfc_in = int(result.group('ndays')) measure = result.group('measr') if measure == None: pass elif measure[0:4] == 'week': mfc_in *= 7 elif measure[0:5] == 'month': mfc_in *= 30 if mfc_in < 0: lprintf('%s: doesn\'t look like a MFC notification request', filename) continue date[3] = date[4] = date[5] = 0 timestamp = time.mktime(tuple(date)) timestamp += mfc_in * SECSADAY date = time.localtime(timestamp) strdate = '%d%02d%02d' % tuple(date[0:3]) destdir = os.path.join(MFCNS_QUEUE, strdate) if not os.path.exists(destdir): os.mkdir(destdir) if not os.path.isdir(destdir): raise IOError(errno.ENOTDIR, 'Not a directory', destdir) os.rename(filename, os.path.join(destdir, os.path.basename(filename))) # Part II. Queue processing timestamp = time.time() cdate = time.localtime(timestamp) today = int('%d%02d%02d' % tuple(cdate[0:3])) mfc_tral_rex = re.compile(MFC_TRAL) do_sleep = 0 for dname in os.listdir(MFCNS_QUEUE): fdir = os.path.join(MFCNS_QUEUE, dname) if not (os.path.isdir(fdir) and len(dname) == 8 and int(dname) <= today): continue for filename in os.listdir(fdir): if do_sleep == 1: time.sleep(SENDBREAK) filename = os.path.join(fdir, filename) if not os.path.isfile(filename): lprintf('%s: not a file found in the queue directory', filename) continue lprintf('Processing "%s"...', filename) fdes = open(filename, 'r', encoding='utf-8') message = message_from_file(fdes) to = parseaddr(message['From']) subject = message['Subject'] branch = message.get('X-FreeBSD-CVS-Branch', None) if branch == None: branch = message['X-SVN-Group'] fdes.seek(0, 0) content = fdes.readlines() fdes.close() i = 0 for line in content: result = mfc_tral_rex.match(line) if result != None: content = content[:i] break i += 1 sendnote(to, subject, branch, content) lprintf('MFC notification sent to "%s" <%s>', to) os.unlink(filename) do_sleep = 1 if len(os.listdir(fdir)) == 0: os.rmdir(fdir) else: lprintf('%s: directory can\'t be deleted because it is not empty', fdir)
def handle(self, *args, **kwargs): for user in User.objects.all(): if user.email is None or user.email == '': if '@' in parseaddr(user.username)[1]: user.email = user.username user.save()
def _format_addr(s): name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr))
def formatAddr(mail): name, addr = parseaddr(mail) return formataddr((Header(name, 'utf-8').encode(), addr))
def validate_email(self, email_str): return "@" in parseaddr(email_str)[1]
def _parse_address(self, address): name, email = parseaddr(address) parsed_address = {'email': email} if name: parsed_address['name'] = name return parsed_address
def post(self): """ POST /login { email: <email>, password: <password> } :return: """ if not self.request.body: self.userError("empty request") return try: data = escape.json_decode(self.request.body) except json.decoder.JSONDecodeError as e: self.userError("Malformed request", e) return except Exception as e: self.userError("Malformed request", e) return if not data['email']: self.userError("Email not specified") return if not data['password']: self.userError("Password not specified") return else: password = data['password'] _, email = parseaddr(data['email']) if not email: self.userError("Wrong Email address") return try: feed = yield r.table('users').filter({"email": email}).run(self.application.dbconnection) yield feed.fetch_next() user = yield feed.next() if not user: self.userError("User does not exists") return except Exception as e: self.userError("User does not exists") return p = bytes(password, 'latin-1') #self.userError("{}".format(p)) if not check_password(password, user['password']): self.userError("password does not match") return # TODO: integrate OAuth2 and pass a token to the user self.set_current_user(user) self.write(json.dumps( { "result": "success", "error": None, "debug": None }, cls=myJSONEncoder))
def _format_addr(s): name, addr = parseaddr(s) return formataddr((name, addr))
def gather_mail(self, email, password, to_addr): """ 读取最新邮件 参数: - email:邮箱地址 - password:授权密码 """ pop3_server = 'pop.' + email.split('@')[-1] # 开始连接到服务器 server = poplib.POP3(pop3_server) # server.set_debuglevel(1) # 认证: server.user(email) server.pass_(password) resp, mails, octets = server.list() # 获取最新一封邮件, 注意索引号从1开始: resp, lines, octets = server.retr(len(mails)) # 解析邮件: msg_content = b'\r\n'.join(lines).decode() msg = Parser().parsestr(text=msg_content) # 获取发件人邮箱地址 value = msg.get("From", '') _, addr = parseaddr(value) # 只有指定的邮箱发起控制指令才会执行 if addr != to_addr: print("无效邮件不执行") return # 获取服务收到邮件时间 received_time = msg.get("Date") received_time = received_time[0:received_time.index("+")] + " GMT" # 格式时间 end = datetime.datetime.strptime(received_time, GMT_FORMAT) # 获取当前时间 start = datetime.datetime.now() # print (start,"--",end,"**********************",(start-end).seconds) if (start - end).seconds > 60 * 2: print("当前指令已经过期不会被执行 ", start - end) return # 检查是否有内容 if (msg.is_multipart()): # 获取内容 内容可能包含两部分 parts = msg.get_payload() # 遍历内容 for _, part in enumerate(parts): # 获取内容类型 text/plain and text/html content_type = part.get_content_type() # 判断是不是纯本部内容 if content_type == 'text/plain': content = part.get_payload(decode=True) charset = self.guess_charset(part) if charset: # 取出邮件内容 content = content.decode(charset) # 去除空格和换行 ctext = content.replace("\n", "").strip() return ctext # 慎重:将直接从服务器删除邮件: # server.dele(len(mails)) # 关闭连接: server.quit()
def __init__(self, subject='', text_body='', html_body='', from_email=None, to=None, cc=None, bcc=None, sender=None, in_reply_to=None, headers=None, auto_generated=False, prevent_auto_responses=False, from_spoofing=None, enable_smart_spoofing=None): """Create a new EmailMessage. Args: subject (unicode, optional): The subject of the message. Defaults to being blank (which MTAs might replace with "no subject".) text_body (unicode, optional): The body of the e-mail as plain text. Defaults to an empty string (allowing HTML-only e-mails to be sent). html_body (unicode, optional): The body of the e-mail as HTML. Defaults to an empty string (allowing text-only e-mails to be sent). from_email (unicode, optional): The from address for the e-mail. Defaults to :django:setting:`DEFAULT_FROM_EMAIL`. to (list, optional): A list of e-mail addresses as :py:class:`unicode` objects that are to receive the e-mail. Defaults to an empty list of addresses (allowing using CC/BCC only). cc (list, optional): A list of e-mail addresses as :py:class:`unicode` objects that are to receive a carbon copy of the e-mail, or ``None`` if there are no CC recipients. bcc (list, optional): A list of e-mail addresses as :py:class:`unicode` objects that are to receive a blind carbon copy of the e-mail, or ``None`` if there are not BCC recipients. sender (unicode, optional): The actual e-mail address sending this e-mail, for use in the :mailheader:`Sender` header. If this differs from ``from_email``, it will be left out of the header as per :rfc:`2822`. This will default to :django:setting:`DEFAULT_FROM_EMAIL` if unspecified. in_reply_to (unicode, optional): An optional message ID (which will be used as the value for the :mailheader:`In-Reply-To` and :mailheader:`References` headers). This will be generated if not provided and will be available as the :py:attr:`message_id` attribute after the e-mail has been sent. headers (django.utils.datastructures.MultiValueDict, optional): Extra headers to provide with the e-mail. auto_generated (bool, optional): If ``True``, the e-mail will contain headers that mark it as an auto-generated message (as per :rfc:`3834`) to avoid auto replies. prevent_auto_responses (bool, optional): If ``True``, the e-mail will contain headers to prevent auto replies for delivery reports, read receipts, out of office e-mails, and other auto-generated e-mails from Exchange. from_spoofing (int, optional): Whether to spoof the :mailheader:`From` header for the user. This can be one of :py:attr:`FROM_SPOOFING_ALWAYS`, :py:attr:`FROM_SPOOFING_SMART`, or :py:attr:`FROM_SPOOFING_NEVER`. This defaults to ``None``, in which case the ``enable_smart_spoofing`` will be checked (for legacy reasons), falling back to ``settings.DJBLETS_EMAIL_FROM_SPOOFING`` (which defaults to :py:attr:`FROM_SPOOFING_ALWAYS`, also for legacy reasons). enable_smart_spoofing (bool, optional): Whether to enable smart spoofing of any e-mail addresses for the :mailheader:`From` header (if ``from_spoofing`` is ``None``). This defaults to ``settings.EMAIL_ENABLE_SMART_SPOOFING``. This is deprecated in favor of ``from_spoofing``. """ headers = headers or MultiValueDict() if (isinstance(headers, dict) and not isinstance(headers, MultiValueDict)): # Instantiating a MultiValueDict from a dict does not ensure that # values are lists, so we have to ensure that ourselves. headers = MultiValueDict( dict((key, [value]) for key, value in six.iteritems(headers))) if in_reply_to: headers['In-Reply-To'] = in_reply_to headers['References'] = in_reply_to headers['Reply-To'] = from_email if from_spoofing is None: if enable_smart_spoofing is None: enable_smart_spoofing = \ getattr(settings, 'EMAIL_ENABLE_SMART_SPOOFING', None) if enable_smart_spoofing is not None: if enable_smart_spoofing: from_spoofing = self.FROM_SPOOFING_SMART else: # This was the original behavior when the setting was # False. from_spoofing = self.FROM_SPOOFING_ALWAYS if from_spoofing is None: from_spoofing = getattr(settings, 'DJBLETS_EMAIL_FROM_SPOOFING', self.FROM_SPOOFING_ALWAYS) # Figure out the From/Sender we'll be wanting to use. if not sender: sender = settings.DEFAULT_FROM_EMAIL if sender == from_email: # RFC 2822 section 3.6.2 states that we should only include Sender # if the two are not equal. We also know that we're not spoofing, # so e-mail sending should work fine here. sender = None elif from_spoofing != self.FROM_SPOOFING_ALWAYS: # If from_spoofing is in smart mode, we will be checking the # DMARC record from the e-mail address we'd be ideally sending on # behalf of. If the record indicates that the message has any # likelihood of being quarantined or rejected, we'll alter the From # field to send using our Sender address instead. # # If from_spoofing is disabled, we will be changing the from_email # to avoid spoofing. parsed_from_name, parsed_from_email = parseaddr(from_email) parsed_sender_name, parsed_sender_email = parseaddr(sender) # The above will return ('', '') if the address couldn't be parsed, # so check for this. if not parsed_from_email: logger.warning( 'EmailMessage: Unable to parse From address ' '"%s"', from_email) if not parsed_sender_email: logger.warning( 'EmailMessage: Unable to parse Sender address ' '"%s"', sender) # We may not be allowed to send on behalf of this user. # We actually aren't going to check for this (it may be due # to SPF, which is too complex for us to want to check, or # it may be due to another ruleset somewhere). Instead, just # check if this e-mail could get lost due to the DMARC rules # or if from_spoofing is disabled. if (from_spoofing == self.FROM_SPOOFING_NEVER or (parsed_from_email != parsed_sender_email and not is_email_allowed_by_dmarc(parsed_from_email))): # Spoofing is disabled or we can't spoof the e-mail address, # so instead, we'll keep the e-mail in Reply To and create a # From address we own, which will also indicate what service # is sending on behalf of the user. from_email = build_email_address_via_service( full_name=parsed_from_name, email=parsed_from_email, sender_email=parsed_sender_email) if sender: headers['Sender'] = sender headers['X-Sender'] = sender if auto_generated: headers['Auto-Submitted'] = 'auto-generated' if prevent_auto_responses: headers['X-Auto-Response-Suppress'] = 'DR, RN, OOF, AutoReply' # We're always going to explicitly send with the DEFAULT_FROM_EMAIL, # but replace the From header with the e-mail address we decided on. # While this class and its parent classes don't really care about the # difference between these, Django's SMTP e-mail sending machinery # treats them differently, sending the value of EmailMessage.from_email # when communicating with the SMTP server. super(EmailMessage, self).__init__(subject=subject, body=force_text(text_body), from_email=settings.DEFAULT_FROM_EMAIL, to=to, cc=cc, bcc=bcc, headers={ 'From': from_email, }) self.message_id = None # We don't want to use the regular extra_headers attribute because # it will be treated as a plain dict by Django. Instead, since we're # using a MultiValueDict, we store it in a separate attribute # attribute and handle adding our headers in the message method. self._headers = headers if html_body: self.attach_alternative(force_text(html_body), 'text/html')
# -*- coding: utf-8 -*- try: import multiprocessing except ImportError: pass try: from setuptools import setup except ImportError: from distutils.core import setup from email.utils import parseaddr import flask_oauthlib author, author_email = parseaddr(flask_oauthlib.__author__) def fread(filename): with open(filename) as f: return f.read() setup(name='Flask-OAuthlib', version=flask_oauthlib.__version__, author=author, author_email=author_email, url=flask_oauthlib.__homepage__, packages=[ "flask_oauthlib", "flask_oauthlib.provider",
def parse(self, m, prefix=None): """Parse messages sent by the svn 'commit-email.pl' trigger. """ # The mail is sent from the person doing the checkin. Assume that the # local username is enough to identify them (this assumes a one-server # cvs-over-rsh environment rather than the server-dirs-shared-over-NFS # model) name, addr = parseaddr(m["from"]) if not addr: return None # no From means this message isn't from svn at = addr.find("@") if at == -1: author = addr # might still be useful else: author = addr[:at] # we take the time of receipt as the time of checkin. Not correct (it # depends upon the email latency), but it avoids the # out-of-order-changes issue. Also syncmail doesn't give us anything # better to work with, unless you count pulling the v1-vs-v2 # timestamp out of the diffs, which would be ugly. TODO: Pulling the # 'Date:' header from the mail is a possibility, and # email.utils.parsedate_tz may be useful. It should be configurable, # however, because there are a lot of broken clocks out there. when = util.now() files = [] comments = "" lines = list(body_line_iterator(m)) rev = None while lines: line = lines.pop(0) # "Author: jmason" match = re.search(r"^Author: (\S+)", line) if match: author = match.group(1) # "New Revision: 105955" match = re.search(r"^New Revision: (\d+)", line) if match: rev = match.group(1) # possible TODO: use "Date: ..." data here instead of time of # commit message receipt, above. however, this timestamp is # specified *without* a timezone, in the server's local TZ, so to # be accurate buildbot would need a config setting to specify the # source server's expected TZ setting! messy. # this stanza ends with the "Log:" if (line == "Log:\n"): break # commit message is terminated by the file-listing section while lines: line = lines.pop(0) if (line == "Modified:\n" or line == "Added:\n" or line == "Removed:\n"): break comments += line comments = comments.rstrip() + "\n" while lines: line = lines.pop(0) if line == "\n": break if line.find("Modified:\n") == 0: continue # ignore this line if line.find("Added:\n") == 0: continue # ignore this line if line.find("Removed:\n") == 0: continue # ignore this line line = line.strip() thesefiles = line.split(" ") for f in thesefiles: if prefix: # insist that the file start with the prefix: we may get # changes we don't care about too if f.startswith(prefix): f = f[len(prefix):] else: log.msg("ignored file from svn commit: prefix '%s' " "does not match filename '%s'" % (prefix, f)) continue # TODO: figure out how new directories are described, set # .isdir files.append(f) if not files: log.msg("no matching files found, ignoring commit") return None return ('svn', dict(author=author, files=files, comments=comments, when=when, revision=rev))
def main(): module = AnsibleModule( argument_spec=dict( username=dict(type='str'), password=dict(type='str', no_log=True), host=dict(type='str', default='localhost'), port=dict(type='int', default=25), sender=dict(type='str', default='root', aliases=['from']), to=dict(type='list', default=['root'], aliases=['recipients']), cc=dict(type='list', default=[]), bcc=dict(type='list', default=[]), subject=dict(type='str', required=True, aliases=['msg']), body=dict(type='str'), attach=dict(type='list', default=[]), headers=dict(type='list', default=[]), charset=dict(type='str', default='utf-8'), subtype=dict(type='str', default='plain', choices=['html', 'plain']), secure=dict(type='str', default='try', choices=['always', 'never', 'starttls', 'try']), timeout=dict(type='int', default=20), ), required_together=[['password', 'username']], ) username = module.params.get('username') password = module.params.get('password') host = module.params.get('host') port = module.params.get('port') sender = module.params.get('sender') recipients = module.params.get('to') copies = module.params.get('cc') blindcopies = module.params.get('bcc') subject = module.params.get('subject') body = module.params.get('body') attach_files = module.params.get('attach') headers = module.params.get('headers') charset = module.params.get('charset') subtype = module.params.get('subtype') secure = module.params.get('secure') timeout = module.params.get('timeout') code = 0 secure_state = False sender_phrase, sender_addr = parseaddr(sender) if not body: body = subject try: if secure != 'never': try: if PY3: smtp = smtplib.SMTP_SSL(host=host, port=port, timeout=timeout) else: smtp = smtplib.SMTP_SSL(timeout=timeout) code, smtpmessage = smtp.connect(host, port) secure_state = True except ssl.SSLError as e: if secure == 'always': module.fail_json( rc=1, msg='Unable to start an encrypted session to %s:%s: %s' % (host, port, to_native(e)), exception=traceback.format_exc()) except Exception: pass if not secure_state: if PY3: smtp = smtplib.SMTP(host=host, port=port, timeout=timeout) else: smtp = smtplib.SMTP(timeout=timeout) code, smtpmessage = smtp.connect(host, port) except smtplib.SMTPException as e: module.fail_json(rc=1, msg='Unable to Connect %s:%s: %s' % (host, port, to_native(e)), exception=traceback.format_exc()) try: smtp.ehlo() except smtplib.SMTPException as e: module.fail_json(rc=1, msg='Helo failed for host %s:%s: %s' % (host, port, to_native(e)), exception=traceback.format_exc()) if int(code) > 0: if not secure_state and secure in ('starttls', 'try'): if smtp.has_extn('STARTTLS'): try: smtp.starttls() secure_state = True except smtplib.SMTPException as e: module.fail_json( rc=1, msg='Unable to start an encrypted session to %s:%s: %s' % (host, port, to_native(e)), exception=traceback.format_exc()) try: smtp.ehlo() except smtplib.SMTPException as e: module.fail_json(rc=1, msg='Helo failed for host %s:%s: %s' % (host, port, to_native(e)), exception=traceback.format_exc()) else: if secure == 'starttls': module.fail_json( rc=1, msg='StartTLS is not offered on server %s:%s' % (host, port)) if username and password: if smtp.has_extn('AUTH'): try: smtp.login(username, password) except smtplib.SMTPAuthenticationError: module.fail_json( rc=1, msg= 'Authentication to %s:%s failed, please check your username and/or password' % (host, port)) except smtplib.SMTPException: module.fail_json( rc=1, msg='No Suitable authentication method was found on %s:%s' % (host, port)) else: module.fail_json(rc=1, msg="No Authentication on the server at %s:%s" % (host, port)) if not secure_state and (username and password): module.warn('Username and Password was sent without encryption') msg = MIMEMultipart(_charset=charset) msg['From'] = formataddr((sender_phrase, sender_addr)) msg['Date'] = formatdate(localtime=True) msg['Subject'] = Header(subject, charset) msg.preamble = "Multipart message" for header in headers: # NOTE: Backward compatible with old syntax using '|' as delimiter for hdr in [x.strip() for x in header.split('|')]: try: h_key, h_val = hdr.split('=') h_val = to_native(Header(h_val, charset)) msg.add_header(h_key, h_val) except Exception: module.warn("Skipping header '%s', unable to parse" % hdr) if 'X-Mailer' not in msg: msg.add_header('X-Mailer', 'Ansible mail module') addr_list = [] for addr in [x.strip() for x in blindcopies]: addr_list.append(parseaddr(addr)[1]) # address only, w/o phrase to_list = [] for addr in [x.strip() for x in recipients]: to_list.append(formataddr(parseaddr(addr))) addr_list.append(parseaddr(addr)[1]) # address only, w/o phrase msg['To'] = ", ".join(to_list) cc_list = [] for addr in [x.strip() for x in copies]: cc_list.append(formataddr(parseaddr(addr))) addr_list.append(parseaddr(addr)[1]) # address only, w/o phrase msg['Cc'] = ", ".join(cc_list) part = MIMEText(body + "\n\n", _subtype=subtype, _charset=charset) msg.attach(part) # NOTE: Backware compatibility with old syntax using space as delimiter is not retained # This breaks files with spaces in it :-( for filename in attach_files: try: part = MIMEBase('application', 'octet-stream') with open(filename, 'rb') as fp: part.set_payload(fp.read()) encoders.encode_base64(part) part.add_header('Content-disposition', 'attachment', filename=os.path.basename(filename)) msg.attach(part) except Exception as e: module.fail_json( rc=1, msg= "Failed to send community.general.mail: can't attach file %s: %s" % (filename, to_native(e)), exception=traceback.format_exc()) composed = msg.as_string() try: result = smtp.sendmail(sender_addr, set(addr_list), composed) except Exception as e: module.fail_json(rc=1, msg="Failed to send mail to '%s': %s" % (", ".join(set(addr_list)), to_native(e)), exception=traceback.format_exc()) smtp.quit() if result: for key in result: module.warn("Failed to send mail to '%s': %s %s" % (key, result[key][0], result[key][1])) module.exit_json(msg='Failed to send mail to at least one recipient', result=result) module.exit_json(msg='Mail sent successfully', result=result)
def is_email_valid(email: str) -> bool: return '@' in parseaddr(email)[1]
USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ STATIC_URL = "/static/" STATIC_ROOT = os.path.join(BASE_DIR, "static") MEDIA_URL = "/media/" MEDIA_ROOT = os.path.join(BASE_DIR, "media") STATICFILES_DIRS = (os.path.join(BASE_DIR, "static_in_dev"), ) CRISPY_TEMPLATE_PACK = "bootstrap4" CHANNEL_LAYERS = { "default": { "BACKEND": "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": [("redis", 6379)], }, }, } admins_data = env.tuple("DJANGO_ADMINS", default="Site <*****@*****.**>") ADMINS = tuple(parseaddr(email) for email in admins_data)
import matplotlib.pyplot as plt except: pass if len(sys.argv) == 1: filePath = "unix_email.mbox" else: filePath = sys.argv[1] mbox = mailbox.mbox(filePath, msgfactory) # parse unix mailbox G = nx.MultiDiGraph() # create empty graph # parse each messages and build graph for msg in mbox: # msg is python email.Message.Message object (source_name, source_addr) = parseaddr(msg['From']) # sender # get all recipients # see http://www.python.org/doc/current/lib/module-email.Utils.html tos = msg.get_all('to', []) ccs = msg.get_all('cc', []) resent_tos = msg.get_all('resent-to', []) resent_ccs = msg.get_all('resent-cc', []) all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) # now add the edges for this mail message for (target_name, target_addr) in all_recipients: G.add_edge(source_addr, target_addr, message=msg) # print edges with message subject for (u, v, d) in G.edges(data=True): print("From: %s To: %s Subject: %s" % (u, v, d['message']["Subject"]))
def format_addr(s): name, addr = parseaddr(s.decode('utf8')) return formataddr( (Header(name, 'utf8').encode(), addr.encode('utf8') if isinstance(addr, unicode) else addr))
pdb.set_trace() index = len(mails) spam_csv = [] ter_csv = [] num = 0 ter_nm = 0 words = set() wordm = set() for v in range(index): try: # resp, lines, octets = server.retr(v+1) resp, lines, octets = server.top(v + 1, 7) msg_content = '\r\n'.join(lines) msg = email.message_from_string(msg_content) fmail = msg.get('From') from_mail = utils.parseaddr(msg.get('From'))[1] nick = fmail.split(' ')[0] if '=' in nick: nick = decode_nck(nick) subject = msg.get('Subject') subject = decode_header(subject)[0][0].replace(' ', '') flag = 0 try: subject = subject.decode('utf8').encode('utf8') except: try: subject = subject.decode('gbk').encode('utf8') except: subject = subject.decode('gb18030').encode('utf8') for word in filter_words: if word in subject:
def target_is_email(self, target): if parseaddr(target)[1] and '@' in target and '.' in target: return True else: return False
def extract_email_address(raw): from email.utils import parseaddr return parseaddr(raw)[-1]
def _decode_message(self, msg): assert isinstance(msg, email.message.Message) headers = { name: self._decode_header(value) for name, value in msg.items() } subject = self._decode_header(msg.get(u'subject', u'')) from_header = self._decode_header(msg.get(u'from', u'')) from_name, from_mail = parseaddr(from_header) text = u'' html = u'' attachments = [] for part in msg.walk(): if part.is_multipart(): continue content_type = part.get_content_type() charset = part.get_content_charset() content = part.get_payload(decode=True) disposition = self._decode_header( part.get(u'Content-Disposition', u'')) is_attachment = disposition.startswith(u'attachment') if not text and content_type == u'text/plain' and not is_attachment: text = self._decode_content(content, charset) elif not html and content_type == u'text/html' and not is_attachment: html = self._decode_content(content, charset) else: default = u'attachment{}'.format( guess_extension(content_type, u'.bin')) filename = part.get_filename(default) attachments.append( Attachment( file=ContentFile(content), name=filename, )) recipients = [] for header_name, type in ((u'to', Recipient.TYPES.TO), (u'cc', Recipient.TYPES.CC), (u'bcc', Recipient.TYPES.BCC)): header = self._decode_header(msg.get(header_name, u'')) for rcp_address in header.split(','): rcp_name, rcp_mail = parseaddr(rcp_address) if rcp_mail: recipients.append( Recipient( name=rcp_name, mail=rcp_mail, type=type, status=Recipient.STATUSES.INBOUND, )) message = Message( type=Message.TYPES.INBOUND, processed=None, from_name=from_name, from_mail=from_mail, subject=subject, text=text, html=html, headers=headers, ) message.save() for recipient in recipients: recipient.message = message recipient.save() for attachment in attachments: attachment.generic_object = message attachment.save() return message
def main(): module = AnsibleModule( argument_spec=dict(username=dict(default=None), password=dict(default=None, no_log=True), host=dict(default='localhost'), port=dict(default='25'), sender=dict(default='root', aliases=['from']), to=dict(default='root', aliases=['recipients']), cc=dict(default=None), bcc=dict(default=None), subject=dict(required=True, aliases=['msg']), body=dict(default=None), attach=dict(default=None), headers=dict(default=None), charset=dict(default='us-ascii'), subtype=dict(default='plain'))) username = module.params.get('username') password = module.params.get('password') host = module.params.get('host') port = module.params.get('port') sender = module.params.get('sender') recipients = module.params.get('to') copies = module.params.get('cc') blindcopies = module.params.get('bcc') subject = module.params.get('subject') body = module.params.get('body') attach_files = module.params.get('attach') headers = module.params.get('headers') charset = module.params.get('charset') subtype = module.params.get('subtype') sender_phrase, sender_addr = parseaddr(sender) if not body: body = subject try: try: smtp = smtplib.SMTP_SSL(host, port=int(port)) except (smtplib.SMTPException, ssl.SSLError): smtp = smtplib.SMTP(host, port=int(port)) except Exception: e = get_exception() module.fail_json( rc=1, msg='Failed to send mail to server %s on port %s: %s' % (host, port, e)) smtp.ehlo() if username and password: if smtp.has_extn('STARTTLS'): smtp.starttls() try: smtp.login(username, password) except smtplib.SMTPAuthenticationError: module.fail_json( msg= "Authentication to %s:%s failed, please check your username and/or password" % (host, port)) msg = MIMEMultipart() msg['Subject'] = subject msg['From'] = formataddr((sender_phrase, sender_addr)) msg.preamble = "Multipart message" if headers is not None: for hdr in [x.strip() for x in headers.split('|')]: try: h_key, h_val = hdr.split('=') msg.add_header(h_key, h_val) except: pass if 'X-Mailer' not in msg: msg.add_header('X-Mailer', "Ansible") to_list = [] cc_list = [] addr_list = [] if recipients is not None: for addr in [x.strip() for x in recipients.split(',')]: to_list.append(formataddr(parseaddr(addr))) addr_list.append(parseaddr(addr)[1]) # address only, w/o phrase if copies is not None: for addr in [x.strip() for x in copies.split(',')]: cc_list.append(formataddr(parseaddr(addr))) addr_list.append(parseaddr(addr)[1]) # address only, w/o phrase if blindcopies is not None: for addr in [x.strip() for x in blindcopies.split(',')]: addr_list.append(parseaddr(addr)[1]) if len(to_list) > 0: msg['To'] = ", ".join(to_list) if len(cc_list) > 0: msg['Cc'] = ", ".join(cc_list) part = MIMEText(body + "\n\n", _subtype=subtype, _charset=charset) msg.attach(part) if attach_files is not None: for file in attach_files.split(): try: fp = open(file, 'rb') part = MIMEBase('application', 'octet-stream') part.set_payload(fp.read()) fp.close() encoders.encode_base64(part) part.add_header('Content-disposition', 'attachment', filename=os.path.basename(file)) msg.attach(part) except Exception: e = get_exception() module.fail_json( rc=1, msg="Failed to send mail: can't attach file %s: %s" % (file, e)) composed = msg.as_string() try: smtp.sendmail(sender_addr, set(addr_list), composed) except Exception: e = get_exception() module.fail_json(rc=1, msg='Failed to send mail to %s: %s' % (", ".join(addr_list), e)) smtp.quit() module.exit_json(changed=False)
def update_thrids(env, folder=None, manual=True, commit=True): where = (env.mogrify('%s = ANY(labels)', [folder]) if folder else env.mogrify('labels && %s::varchar[]', [list(FOLDERS)])) emails = env.sql(''' SELECT id, fr, sender, "to", cc, subj, labels, array_prepend(in_reply_to, refs) AS refs FROM emails WHERE thrid IS NULL AND {where} ORDER BY id '''.format(where=where)).fetchall() log.info(' * Update thread ids for %s emails', len(emails)) def yet(condition): if thrid and pid: return False return condition t, updated = Timer(), [] for row in emails: thrid = pid = None refs = [r for r in row['refs'] if r] ctx = {'folder': folder or (set(FOLDERS) & set(row['labels'])).pop()} m_label = [l for l in row['labels'] if l.startswith('%s/' % THRID)] if manual and m_label: # Manual thread extid = m_label.pop().replace('%s/' % THRID, '') thrid = env.sql( ''' SELECT id FROM emails WHERE extid=%(extid)s AND %(folder)s = ANY(labels) ''', dict(ctx, extid=extid)).fetchone() if thrid: thrid = thrid[0] if yet(row['fr'][0].endswith('<*****@*****.**>')): # Failed delivery text = env.sql('SELECT text FROM emails WHERE id=%s', [row['id']]) text = text.fetchone()[0] msgid = re.search('(?m)^Message-ID:(.*)$', text) if msgid: msgid = msgid.group(1).strip() parent = env.sql( ''' SELECT id, thrid FROM emails WHERE %(folder)s = ANY(labels) AND msgid=%(msgid)s ORDER BY id DESC LIMIT 1 ''', dict(ctx, msgid=msgid)).fetchone() if parent: thrid = thrid or parent['thrid'] pid = pid or parent['id'] if yet(refs): parent = env.sql( ''' SELECT id, thrid FROM emails WHERE %(folder)s = ANY(labels) AND msgid = %(ref)s ORDER BY id DESC LIMIT 1 ''', dict(ctx, ref=refs[0])).fetchone() if not parent and refs: parent = env.sql( ''' SELECT id, thrid FROM emails WHERE %(folder)s = ANY(labels) AND (in_reply_to || refs) && %(refs)s::varchar[] ORDER BY id DESC LIMIT 1 ''', dict(ctx, refs=refs)).fetchone() if parent: thrid = thrid or parent['thrid'] pid = pid or parent['id'] if yet(row['fr'] and row['to']): fr = row['sender'][0] if row['sender'] else row['fr'][0] fr = parseaddr(fr)[1] parent = env.sql( ''' SELECT id, thrid FROM emails WHERE %(folder)s = ANY(labels) AND id < %(id)s AND subj LIKE %(subj)s AND array_to_string(sender || fr || "to" || cc, ',') LIKE %(fr)s AND (sender || fr || "to" || cc) && %(to)s::varchar[] ORDER BY id DESC LIMIT 1 ''', dict( ctx, **{ 'subj': '%{}'.format(row['subj']) if row['subj'] else '', 'fr': '%<{}>%'.format(fr), 'to': row['to'] + row['cc'], 'id': row['id'], })).fetchone() if parent: thrid = thrid or parent['thrid'] pid = pid or parent['id'] updates = {'thrid': thrid if thrid else row['id'], 'parent': pid} env.emails.update(updates, 'id=%s', [row['id']]) updated.append(row['id']) if updated: env.db.commit() log.info(' - for %.2fs', t.time()) return updated