概述 MUA:Mail User Agent——邮件用户代理
MTA:Mail Transfer Agent——邮件传输代理,Email服务提供商(网易、新浪…)
MDA:Mail Delivery Agent——邮件投递代理,Email到达MDA后,就静静地躺在Email服务提供商的某个服务器上,存放在某个文件或特殊的数据库里,这个长期保存邮件的地方称之为电子邮箱。
一封电子邮件的旅程:
1 发件人 -> MUA -> MTA -> MTA -> 若干个MTA -> MDA <- MUA <- 收件人
要编写程序来发送和接收邮件,本质上就是:
编写MUA把邮件发到MTA;
编写MUA从MDA上收邮件。
发邮件时,MUA和MTA使用的协议就是SMTP:Simple Mail Transfer Protocol,后面的MTA到另一个MTA也是用SMTP协议。
收邮件时,MUA和MDA使用的协议有两种:POP:Post Office Protocol,目前版本是3,俗称POP3;IMAP:Internet Message Access Protocol,目前版本是4,优点是不但能取邮件,还可以直接操作MDA上存储的邮件,比如从收件箱移到垃圾箱,等等。
示例 SMTP——发送:mail_send.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import smtplib from email.mime.text import MIMEText from email.header import Header from email.utils import formataddr from_addr = 'me@163.com' password = 'UKd9g3eQrF9PQa' to_addr = 'me@qq.com' smtp_server = 'smtp.163.com' msg = MIMEText('hello, send by Python' , 'plain' , 'utf-8' ) msg['From' ] = formataddr(('发件人007' , from_addr)) msg['To' ] = formataddr(('收件人009' , to_addr)) msg['Subject' ] = Header('测试邮件标题' , 'utf-8' )try : server = smtplib.SMTP_SSL(smtp_server, 465 ) server.set_debuglevel(1 ) server.login(from_addr, password) server.sendmail(from_addr, [to_addr], msg.as_string()) print ("✅ 发送成功" )except Exception as e: print (f"❌ 发送失败: {e} " ) finally : server.quit()
POP——接收:mail_receive.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 import poplibfrom email.parser import BytesParserfrom email.header import decode_headerfrom email.utils import parseaddr mail_host = 'pop.qq.com' mail_user = 'me@qq.com' mail_pass = 'zozyyffjbfdhhc' def decode_str (s ): """解码邮件头部中文""" if not s: return '' value, charset = decode_header(s)[0 ] if isinstance (value, bytes ): return value.decode(charset or 'utf-8' ) return valuedef decode_addr (s ): """解码显示名 + 保留邮箱地址,输出:名字 <邮箱>""" if not s: return '' name, addr = parseaddr(s) decoded_name = decode_str(name) if decoded_name: return f"{decoded_name} <{addr} >" return addr server = None try : server = poplib.POP3_SSL(mail_host, 995 ) server.set_debuglevel(1 ) server.user(mail_user) server.pass_(mail_pass) msg_count, mailbox_size = server.stat() print (f"📬 共 {msg_count} 封邮件,总大小 {mailbox_size} 字节\n" ) for i in range (1 , msg_count + 1 ): print (f"{'=' *40 } " ) print (f"📧 第 {i} 封邮件" ) resp, lines, octets = server.retr(i) msg = BytesParser().parsebytes(b'\r\n' .join(lines)) print (f"主题:{decode_str(msg['Subject' ])} " ) print (f"发件人:{decode_addr(msg['From' ])} " ) print (f"收件人:{decode_addr(msg['To' ])} " ) print (f"时间:{msg['Date' ]} " ) if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == 'text/plain' : charset = part.get_content_charset() or 'utf-8' print (f"正文:\n{part.get_payload(decode=True ).decode(charset)} " ) else : charset = msg.get_content_charset() or 'utf-8' print (f"正文:\n{msg.get_payload(decode=True ).decode(charset)} " ) print ()except Exception as e: print (f"❌ 收取失败: {e} " )finally : if server: server.quit()
摘自:https://liaoxuefeng.com/books/python/email/index.html