邮件发送/接收
简单的文本邮件
代码1
1 #不知道为啥这个代码有时候发送成功,有时候发送不成功,简略的测试了一下大概10次中能成功4次 2 #!/usr/bin/python 3 4 import smtplib 5 from email.mime.text import MIMEText 6 from email.header import Header 7 8 pwd_file = open('163mail.txt', 'r') 9 sender_file = open('senders.txt', 'r') 10 receiver_file = open('receivers.txt', 'r') 11 12 pwd = pwd_file.read() 13 sender = sender_file.read() 14 receiver = receiver_file.read() 15 16 pwd_file.close() 17 sender_file.close() 18 receiver_file.close() 19 20 message = MIMEText('Python 邮件发送测试...', 'plain', 'utf-8') 21 message['From'] = sender 22 message['To'] = receiver 23 24 subject = 'Python SMTP 邮件测试' 25 message['Subject'] = Header(subject, 'utf-8') 26 27 try: 28 smtpObj = smtplib.SMTP_SSL('smtp.163.com', 465) 29 smtpObj.login(sender, pwd) 30 smtpObj.sendmail(sender, receiver, message.as_string()) 31 print('邮件发送成功') 32 except smtplib.SMTPException as e: 33 print('Error: 无法发送邮件.Case:%s' % e)
代码2
1 #!/usr/bin/python3 2 3 import smtplib 4 import email.mime.multipart 5 import email.mime.text 6 7 pwd_file = open('163mail.txt', 'r') 8 sender_file = open('senders.txt', 'r') 9 receiver_file = open('receivers.txt', 'r') 10 11 pwd = pwd_file.read() 12 sender = sender_file.read() 13 receiver = receiver_file.read() 14 15 pwd_file.close() 16 sender_file.close() 17 receiver_file.close() 18 19 Subject = 'Subject' 20 From = 'From' 21 To = 'To' 22 23 msg = email.mime.multipart.MIMEMultipart() 24 25 msg[Subject] = 'happy' #非常奇怪的是这里有些字符串不能用,如hello, he,hi等 26 msg[From] = sender 27 msg[To] = receiver 28 29 #邮件正文 30 content = ''' 31 hello world! 32 ''' 33 34 txt = email.mime.text.MIMEText(content) 35 msg.attach(txt) 36 37 try: 38 smtp = smtplib.SMTP() 39 smtp.connect('smtp.163.com', '25') 40 smtp.login(sender, pwd) 41 smtp.sendmail(sender, receiver, msg.as_string()) 42 smtp.quit() 43 print('email sent successfully!') 44 except smtplib.SMTPException as e: 45 print('email failed!\n%s' % e)
发送 html 格式的邮件
如果要发送 html 邮件而非纯文本文件,将上面的代码1稍微修改一下即可:
在构造 MIMEText 对象时把 html 字符串传进去,再把第二个参数由 plain 变为 html 即可
代码:
1 #!/usr/bin/python 2 3 import smtplib 4 from email.mime.text import MIMEText 5 from email.header import Header 6 7 pwd_file = open('163mail.txt', 'r') 8 sender_file = open('senders.txt', 'r') 9 receiver_file = open('receivers.txt', 'r') 10 11 pwd = pwd_file.read() 12 sender = sender_file.read() 13 receiver = receiver_file.read() 14 15 pwd_file.close() 16 sender_file.close() 17 receiver_file.close() 18 19 mail_msg = ''' 20 <p>python 邮件发送测试</p> 21 <p><a href = "http://www.runoob.com">这是一个链接</a></p> 22 ''' 23 24 message = MIMEText(mail_msg, 'html', 'utf-8') 25 message['From'] = sender 26 message['To'] = receiver 27 28 subject = 'Python SMTP 邮件测试' 29 message['Subject'] = Header(subject, 'utf-8') 30 31 try: 32 smtpObj = smtplib.SMTP_SSL('smtp.163.com', 465) 33 smtpObj.login(sender, pwd) 34 smtpObj.sendmail(sender, receiver, message.as_string()) 35 print('邮件发送成功') 36 except smtplib.SMTPException as e: 37 print('Error: 无法发送邮件.Case:%s' % e)
发送带附件的邮件
带附件的邮件可以看作包含文本和各个附件,可以构建一个 MIMEMultipart 对象代表邮件本身,然后往里面添加一个 MIMEText 作为邮件正文,再添加表示附件的 MIMEBase 对象即可
代码:
1 #!/usr/bin/python 2 3 import smtplib 4 from email.mime.text import MIMEText 5 from email.mime.multipart import MIMEMultipart 6 from email.header import Header 7 8 pwd_file = open('163mail.txt', 'r') 9 sender_file = open('senders.txt', 'r') 10 receiver_file = open('receivers.txt', 'r') 11 12 pwd = pwd_file.read() 13 sender = sender_file.read() 14 receiver = receiver_file.read() 15 16 pwd_file.close() 17 sender_file.close() 18 receiver_file.close() 19 20 message = MIMEMultipart() #创建一个带附件的实例 21 message['From'] = sender 22 message['To'] = receiver 23 subject = 'Python SMTP 邮件测试' 24 message['Subject'] = Header(subject, 'utf-8') 25 26 #邮件正文 27 content = ''' 28 # this is a python mail test. 29 ''' 30 message.attach(MIMEText(content, 'plain', 'utf-8')) 31 32 #构造附件1,传送当前目录下的 test.txt 文件 33 att1 = MIMEText(open('test.txt', 'rb').read(), 'base64', 'utf-8') 34 att1['Content-Type'] = 'application/octed-stream' 35 # 这里的filename可以任意些,写什么名字,邮件中就显示什么名字 36 att1['Content-Disposition'] = 'attachment;filename="test.txt"' 37 message.attach(att1) 38 39 #构造附件2,发送 HELLO.ASM 文件 40 att2 = MIMEText(open('D://Project/HELLO.ASM', 'rb').read(), 'base64', 'utf-8') 41 att2['Content-Type'] = 'application/octed-stream' 42 att2['Content-Disposition'] = 'attachment;filename="HELLO.ASM"' 43 message.attach(att2) 44 45 #依此类推可以构造附件 3, 4, 5... 46 47 try: 48 smtp = smtplib.SMTP() 49 smtp.connect('smtp.163.com', '25') 50 smtp.login(sender, pwd) 51 smtp.sendmail(sender, receiver, message.as_string()) 52 smtp.quit() 53 print('email sent successfully!') 54 except smtplib.SMTPException as e: 55 print('email failed!\n%s' % e) 56 57 # try: 58 # smtpObj = smtplib.SMTP_SSL('smtp.163.com', 465) 59 # smtpObj.login(sender, pwd) 60 # smtpObj.sendmail(sender, receiver, message.as_string()) 61 # print('邮件发送成功') 62 # except smtplib.SMTPException as e: 63 # print('Error: 无法发送邮件.Case:%s' % e)
发送图片
代码:
1 #!/usr/bin/python3 2 3 import smtplib 4 import email.mime.multipart 5 import email.mime.text 6 import email.mime.image 7 8 pwd_file = open('163mail.txt', 'r') 9 sender_file = open('senders.txt', 'r') 10 receiver_file = open('receivers.txt', 'r') 11 12 pwd = pwd_file.read() 13 sender = sender_file.read() 14 receiver = receiver_file.read() 15 16 pwd_file.close() 17 sender_file.close() 18 receiver_file.close() 19 20 Subject = 'Subject' 21 From = 'From' 22 To = 'To' 23 24 msg = email.mime.multipart.MIMEMultipart('related')#设置为多文本格式 25 26 msg[Subject] = 'happy' #非常奇怪的是这里有些字符串不能用,如hello, he,hi等 27 msg[From] = sender 28 msg[To] = receiver 29 30 #不能直接将图片和文本一起放到一个MIMEMultipart对象中,不然会收不到内容(即使邮件发送成功)。 31 #可以将图片装入一个MIMEMultipart对象中,再将此MIMEMultipart和文本一起放入另一个MIMEMultipart对象中 32 msg_image = email.mime.multipart.MIMEMultipart('alternative') 33 msg.attach(msg_image) 34 35 #邮件正文 36 content = ''' 37 <p>python 邮件发送测试</p> 38 <p>图片演示: </p> 39 <p><img src = "cid:image1"></p> 40 ''' 41 42 txt = email.mime.text.MIMEText(content, 'html', 'utf-8') 43 msg.attach(txt) 44 45 #读取图片并添加邮件头 46 fp = open('D://photos/test.jpg', 'rb') 47 m_image = email.mime.image.MIMEImage(fp.read()) 48 fp.close() 49 50 m_image.add_header('Content-ID', '<image1>') 51 msg_image.attach(m_image) 52 53 indx = 50 54 while indx: 55 try: 56 smtp = smtplib.SMTP() 57 smtp.connect('smtp.163.com', '25') 58 smtp.login(sender, pwd) 59 smtp.sendmail(sender, receiver, msg.as_string()) 60 smtp.quit() 61 print('email sent successfully!') 62 break; 63 except smtplib.SMTPException as e: 64 print('email failed!\n%s' % e) 65 print('') 66 indx -= 1
注意:不能直接将图片和文本一起放到一个 MIMEMultipart 对象中,不然会收不到内容(即使邮件发送成功)。可以将图片装入一个 MIMEMultipart 对象中,再将此 MIMEMultipart 和文本一起放入另一个 MIMEMultipart 对象中
163 邮箱 554 错误:
554 DT:SPM 发送的邮件内容包含了未被许可的信息,或被系统识别为垃圾邮件。请检查是否有用户发送病毒或者垃圾邮件;
554 DT:SUM 信封发件人和信头发件人不匹配;
554 IP is rejected, smtp auth error limit exceed 该IP验证失败次数过多,被临时禁止连接。请检查验证信息设置;
554 HL:IHU 发信IP因发送垃圾邮件或存在异常的连接行为,被暂时挂起。请检测发信IP在历史上的发信情况和发信程序是否存在异常;
554 HL:IPB 该IP不在网易允许的发送地址列表里;
554 MI:STC 发件人当天内累计邮件数量超过限制,当天不再接受该发件人的投信。请降低发信频率;
554 MI:SPB 此用户不在网易允许的发信用户列表里;
554 IP in blacklist 该IP不在网易允许的发送地址列表里。
pop3 接收邮件
收取邮件就是编写一个 MUA 作为客户端,从 MDA 获取邮件到用户的电脑或手机上。Python 内置了一个 poplib 模块,用于实习 pop3 协议,可以直接用来接收邮件。
注意:pop3 协议收取的不是可以阅读的邮件,而不是邮件的文本。还需要用 email 模块提供的各种类解析原始文本
收取邮件分为以下两个步骤:
1.用 poplib 把邮件的原始文本下载到本地
2. 用 email 解析原始文本,还原为邮件对象
代码:
1 #!/usr/python3 2 #-*-coding:utf-8-*- 3 4 from email.parser import Parser 5 from email.header import decode_header 6 from email.utils import parseaddr 7 import poplib 8 9 10 # 编码转换 11 def decode_str(s): 12 value, charset = decode_header(s)[0] 13 if charset: 14 value = value.decode(charset) 15 return value 16 17 18 def guess_charset(msg): 19 charset = msg.get_charset() 20 if charset is None: 21 content_type = msg.get('Content-Type', ).lower() 22 pos = content_type.find('charset=') 23 if pos >= 0: 24 charset = content_type[pos + 8:].strip() 25 return charset 26 27 28 # indent用于缩进显示 29 def print_info(msg, indent = 0): 30 if indent == 0: 31 for header in ['From', 'To', 'Subject']: 32 value = msg.get(header,) 33 if value: 34 if header == 'Subject': 35 value = decode_str(value) 36 else: 37 hdr, addr = parseaddr(value) 38 name = decode_str(hdr) 39 value = u'%s<%s>'%(name, addr) 40 print('%s%s:%s' % (' '*indent, header, value)) 41 if(msg.is_multipart()): 42 parts = msg.get_payload() 43 for n, part in enumerate(parts): 44 print('%spart %s' % (' '*indent, n)) 45 print('%s---------------' % (' ' * indent)) 46 print_info(part, indent + 1) 47 else: 48 content_type = msg.get_content_type() 49 if(content_type == 'text/plain' or content_type == 'text/html'): 50 content = msg.get_payload(decode = True) 51 charset = guess_charset(msg) 52 if charset: 53 content = content.decode(charset) 54 print('%sText: %s' % (' ' *indent, content + '...')) 55 else: 56 print('%sAttachment:%s' % (' '*indent, content_type)) 57 58 59 60 #输入邮件地址、口令和pop3服务器地址 61 pwd_file = open('163mail.txt', 'r') 62 sender_file = open('senders.txt', 'r') 63 64 email = sender_file.read() 65 password = pwd_file.read() 66 pop3_server = 'pop.163.com' 67 68 pwd_file.close() 69 sender_file.close() 70 71 #连接到pop3服务器 72 server = poplib.POP3(pop3_server) 73 #可以打开或关闭调试信息 74 server.set_debuglevel(1) 75 #可选:输出pop3服务器的欢迎文字 76 print(server.getwelcome().decode('utf-8')) 77 78 #身份认证 79 server.user(email) 80 server.pass_(password) 81 82 #stat()返回邮件数量和占用空间 83 Messages,Size = server.stat() 84 print('Messages:%s. Size:%s' % (Messages, Size)) 85 #list()返回所有邮件的编号 86 resp,mails,octets = server.list() 87 #查看返回列表 88 print(mails) 89 90 #获取最新一封邮件,注意索引号从1开始 91 index = len(mails) 92 resp,lines,octets = server.retr(index) 93 94 #lines存储了邮件原始文本的每一行 95 #可以获得整个邮件的原始文本 96 msg_content = b'\r\n'.join(lines).decode('utf-8') 97 #解析邮件 98 msg = Parser().parsestr(msg_content)#将邮件内容解析为Messege对象 99 print_info(msg, index) 100 # print('\\\\\\\\\\\\') 101 # print_info(msg, index - 1) 102 103 #可以根据邮件索引号直接从服务器删除邮件 104 #server.dele(index) 105 # for i in range(1, Messages + 1): 106 # server.dele(i) 107 server.quit()
上面的代码文件解析的还是有些混乱,本来打算整个简单的收发邮件的客户端也没弄。打个比赛回来啥都不想动了,以后要用的时候再来完善好了。