博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【python3的进阶之路二】因特网客户端编程 实战
阅读量:6919 次
发布时间:2019-06-27

本文共 6556 字,大约阅读时间需要 21 分钟。

一、生成电子邮件

      电子邮件消息不仅包含纯文本,还有附件、文本中的格式等,这种较长的消息由多个部分组成。比如消息中由纯文本的部分,可能还有对应的HTML部分,这部分针对使用web浏览器作为邮件客户端的情形,除此之外还有一个或多个附件。邮件互换消息扩展(Mail Interchange Message Extension, MIME)格式就用来识别这些不同的部分。

from email.mime.image import MIMEImagefrom email.mime.multipart import MIMEMultipartfrom email.mime.text import MIMETextfrom smtplib import SMTP# multipart alternative:test and htmldef make_mpa_msg():    email = MIMEMultipart('alternative')   # 创建一个带附件的实例    text = MIMEText('Hello World!\r\n', 'plain')   # 可包含三个参数,参数一文本内容,参数二plain设置文本格式,参数三UTF-8设置编码    email.attach(text)    html = MIMEText(        '

Hello World!

' '', 'html') email.attach(html) # 添加到邮件正文 return email# multipart:imagesdef make_img_msg(fn): f = open(fn, 'rb') data = f.read() f.close() email = MIMEImage(data, name = fn) email.add_header("Content-Disposition", "attachment; filename = '%s'" % fn) return emaildef sendMsg(fr, to, msg): s = SMTP('smtp.exmail.qq.com') mail_user = 'garcia.cao@rccchina.com' # 用户名 mail_pass = '147qazQAZ' # 密码 s.login(mail_user, mail_pass) errs = s.sendmail(fr, to, msg) s.quit()if __name__ == '__main__': SENDER = 'garcia.cao@rccchina.com' RECIPS = ['garcia.cao@rccchina.com'] SOME_IMG_FILE = 'image.PNG' print('Sending multipart alternative msg...') msg = make_mpa_msg() msg['From'] = SENDER msg['To'] = ', '.join(RECIPS) msg['Subject'] = 'multipart alternative test' sendMsg(SENDER, RECIPS, msg.as_string()) print('Sending image msg...') msg = make_img_msg(SOME_IMG_FILE) msg['From'] = SENDER msg['To'] = ', '.join(RECIPS) msg['Subject'] = 'image file test' sendMsg(SENDER, RECIPS, msg.as_string())

MimeMulipart的三种子类型:mixed、alternative、related

二、解析电子邮件

解析电子邮件一般用到email包中几个方法

def processMsg(entire_mag):    body = ''    msg = email.message_from_string(entire_mag)         # 用来解析消息    if msg.is_multipart(): # 如果邮件对象是一个MIMEMultipart        for part in msg.walk():                # 遍历消息的附件            if part.get_content_type() == 'text/plain':     # 获取正确MIME类型                body = part.get_payload()                   # get_payload()返回list,包含所有的子对象                # 从消息正文中获取特定的部分。通常decode标记设为True,即邮件正文根据每个Content-Transfer-Encoding头解码                break            else:                body = msg.get_payload(decode=True)    else:        body = msg.get_payload(decode=True)    return body

三、最佳实践:安全、重构

from smtplib import SMTP_SSLfrom poplib import POP3_SSLfrom imaplib import IMAP4_SSLfrom secret import *  # where MAILBOX , PASSWORD come fromwho = ''  # xxx@yahoo/gmail.com where MAILBOX = xxxfrom_ = whoto = [who]headers = [    'From: %s' % from_,    'To: %s' % ', '.join(to),    'Subject: test SMTP send via 465/SSL',]body = [    'Hello',    'World!',]msg = '\r\n\r\n'.join(('\r\n'.join(headers), '\r\n'.join(body)))

      首先,在实际的开发环境中,需要加密WEB上的连接,所以使用三个协议的SSL等价版本。其次,不能在代码中使用纯文本保存登录名和密码,这些信息要从安全的数据库、编译的字节码文件(.pyc或.pyo文件)、公司内联网中的服务器代理中获取。

      在这里邮件消息使用列表替换字符串,是因为在实际中,电子邮件消息正文是由应用生成或控制的,而不是硬编码的字符串。当邮件已经准备发送时,只需使用\r\n对调用str.join()就可以组装成正文(\r\n是兼容RFC5322的SMTP的服务器使用的正式分隔符,其他有些服务器至接受换行符)
      邮件的收件人可能不止一个,所以to也是列表形式,在创建最终的电子邮件头时需要使用str.join()将收件人连接到一起。

def getSubject(msg, default = '(no Subject line)'):    '''\    getSubject(msg) = 'msg' is an iterable, not a    delimited single string; this function iterates    over 'msg' look for Subject: line and returns    if found, else the default is returned if one isn`t    found in the headers     :param msg:     :param default:     :return:     '''    for line in msg:        if line.startswith('Subject:'):            return line.rstrip()        if not line:            return default

      查看在Yahoo!Mail和Gmail实例中会用到一个特殊功能函数,该函数仅仅获取入站电子邮件消息的Subject行。getSubject()只查找邮件标题中的Subject行。如果发现一个该函数就立即返回;如果遇到空行表示邮件标题已结束,则返回一个默认值。

      从性能考虑有些人或使用line[:8] == 'Subject’来避免调用 str.startswith()方法,虽然line[:8] == 'Subject’会调用str.getslice(),但这种方法比str.startswith()快40%。

四、Yahoo!Mail!

      该例子,需要一个Yahoo!Mail Plus账号。POP无法无法获取发送的邮件,但IMAP可以找到相应的邮件。

s = SMTP_SSL('smtp.mail.yahoo.com', 465)s.login(MAILBOX, PASSWORD)s.sendmail(from_, to, msg)s.quit()print('SSL: mail sent!')s = POP3_SSL('pop.mail.yahoo.com', 995)s.user(MAILBOX)s.pass_(PASSWORD)rv, msg ,sz = s.retr(s.stat()[0])s.quit()line = getSubject(msg)print('POP:', line)s = IMAP4_SSL('imap.n.mail.yahoo.com', 993)s.login(MAILBOX, PASSWORD)rsp, msgs = s.select('INBOX', True)rsp, data = s.fetch(msgs[0], '(RFC822)')line = getSubject(StringIO(data[0][1]))s.close()s.quit()print('IMAP:', line)

yahoo邮箱已无法注册,以下代码无法调试

from imaplib import  IMAP4_SSLfrom platform import python_versionfrom poplib import POP3_SSL, error_protofrom socket import errorfrom io import StringIO# SMTP_SSL added in 2.6, fixed in 2.6.3release = python_version()if release > '2.6.2':    from smtplib import SMTP_SSL, SMTPServerDisconnectedelse:    SMTP_SSL = Nonefrom secret import *  # you provide MAILBOX, PASSWORDwho = '%s@yahoo.com' % MAILBOXfrom_ = whoto = [who]headers = [    'From: %s' % from_,    'To: %s' ', '.join(to),    'Subject: test SMTP send via 465/SSL',]body = [    'Hello',    'world!',]msg = '\r\n\r\n'.join(('\r\n'.join(headers), '\r\n'.join(body)))def getSubject(msg, default = '(no Subject line)'):    '''\    getSubject(msg) - iterate over 'msg' looking for    Subject line ; return if found otherwise 'default'    '''    for line in msg:        if line.startswith('Subject:'):            return line.rstrip()        if not line:            return default#SMTP/SSLprint('*** Doing SMTP send via SSL...')if SMTP_SSL:    try:        s = SMTP_SSL('smtp.mail.yahoo.com', 465)        s.login(MAILBOX, PASSWORD)        s.sendmail(from_, to, msg)        s.quit()        print('SSL mail sent!')    except SMTPServerDisconnected:        print('error: server unexpectedly disconnected...try again')else:    print('error: SMTP_SSL requires 2.6.3+')# POPprint('***Doing POP recv...')try:    s = POP3_SSL('pop.mail.yahoo.com', 995)    s.user(MAILBOX)    s.pass_(PASSWORD)    rv, msg, sz = s.retr(s.stat()[0])    s.quit()    line = getSubject(msg)    print('Received msg via POP: %r' % line)except error_proto:    print('error: POP for Yahoo!Mail Plus subscribers only')# IMAPprint('***Doing IMAP recv...')try:    s = IMAP4_SSL('imap.n.mail.yahoo.com', 993)    s.login(MAILBOX, PASSWORD)    rsp, msgs = s.select('INBOX', True)    rsp, data = s.fetch(msgs[0], '(RFC822)')    line = getSubject(StringIO(data[0][1]))    s.close()    s.logout()    print('Received msg via IMAP: %r' % line)except error:    print('error: IMAP for Yahoo!Mail Plus subscribers only')

 

转载于:https://www.cnblogs.com/CSgarcia/p/9883121.html

你可能感兴趣的文章