python 发送邮件connect none_Python发送邮件(多收件、多抄送、多表格、多附件)...

本文介绍了使用smtplib发送包含多收件人、多抄送、多表格和多附件的Python邮件。重点包括确认邮箱协议、端口、安全模式,处理中文乱码问题,以及解决SMTPServerDisconnected异常。提供了完整的发送邮件示例代码。
摘要由CSDN通过智能技术生成

1. 前言

利用 smtplib 发送邮件的基础教程也不少,本文不多加阐述,完整代码贴在文后,代码中注释已详细说明,这里就大概说说需要注意的要点。

2. 要点

确认邮箱使用的协议与加密方式

搞清楚邮箱服务商所提供的协议,是否支持 stmp,是否只支持 SSL。印象中,腾讯企业邮箱或者QQ邮箱都是使用 SSL 加密,此时我们必须使用 SMTP_SSL。

确认邮箱提供 IMAP/SMTP 服务的地址与端口

跟以往不同的是,用非官方途径利用官方的邮箱服务器发送邮件,就要拿到该邮箱提供的服务器地址与端口,并在邮箱设置里开启 IMAP/SMTP 服务。例如腾讯企业邮箱的地址便是 smtp.exmaill.qq.com,端口号 465。

邮箱安全模式

若邮箱开启了安全模式,如腾讯企业邮箱,客户端专用密码将代替邮箱的登录密码。则此时我们利用邮箱 IMAP/SMTP 服务的登录密码,需要填客户端专用密码而非邮箱的登录密码。

发送 html 格式内容,例如 html 表格

将容纳正文的容器 MIMEText() 指定格式为 html 即可。此时邮件正文将以 html 格式展现。我们可以利用 html 实现表格的构造,涉及到 html 语言,可参考 将 DataFrame 转为 html 格式文本。

邮件收件人发件人标题中文乱码

邮件中的字符串采用 RFC 格式,至于这个格式怎么编码就交给 smtplib,而我们要做的是,将字符串在编码成 RFC 前解码为 utf-8。即代码中 Header().encode 函数。

邮件正文中文乱码

将 MIMEText() 指定编码 utf-8。

附件文件中文名乱码

需给容纳附件的容器添加信息头时,指定 filename 参数将标题名编码成 gbk。

SMTPServerDisconnected: Connection unexpectedly closed: The read operation timed out

虽然报错,但邮件确实是发送成功了,好像没什么异常情况,这点我好像与别人不一样。所以可以取巧,使用

try:

...

except smtplib.SMTPServerDisconnected:

pass

捕捉异常后 pass 即可。

而真正的做法是, smtplib.SMTP_SSL() 函数添加参数 timeout = 10。此处考虑若发送多个大文件的情况,数值大小看个人情况考虑,数值单位为秒。报错的具体原因个人猜测是附件还未发送成功,server 就 quit 导致的报错。

3. 利用 smtplib 模拟发件过程

from email import encoders

from email.header import Header

from email.mime.text import MIMEText

from email.utils import formataddr

from email.mime.multipart import MIMEMultipart

from email.mime.base import MIMEBase

import os

import smtplib

def send_email(from_addr, to_addr, mailhost, password, msg_subject, msg_text,

cc_addr=None, text_type='plain', file_path=None):

"""

from_addr: dict, 发件人的邮箱昵称和地址, 例如 {'吴刚':'wugang@example.com'}

to_addr: dict, 收件人的邮箱昵称和地址, 例如 {'a':'abc@qq.com', 'b':'efg@163.com'}

mailhost: tuple or list, 邮箱服务器地址和端口, 例如 ('smtp.exmail.qq.com', 465)

password: str, 密码或授权码

msg_subject: str, 邮件的标题

msg_text: str, 邮件的正文

cc_addr: dict, 抄送人的邮箱昵称和地址, 例如 {'小明': 'xiaoming@example.com'}

text_type: str, 发送邮件的文本格式, default 'plain' ,普通文本用此即可,发送html表格

则使用 'html'

file_path: str, 附件文件路径

"""

msg = MIMEMultipart() # 发送附件需要建立容器 MIMEMultipart,

# 如不需要发送附件,可直接建立容器 MIMEText

msg['From'] = _format_addr(from_addr) # 发送人

msg['To'] = _format_addr(to_addr) # 收件人

if cc_addr is not None:

msg['Cc'] = _format_addr(cc_addr) # 抄送人

msg['Subject'] = Header(msg_subject, 'utf-8').encode() # 邮件主题

msg.attach(MIMEText(msg_text, text_type, 'utf-8')) # 指定文本格式为简洁,编码 utf-8

if file_path is not None:

msg = files(msg, file_path) # 读取附件

smtp_server, port = mailhost # 邮箱服务器以及端口号

# 使用 smtp 协议以及 ssl 加密方式

server = smtplib.SMTP_SSL(smtp_server, int(port), timeout=10.0)

server.set_debuglevel(0) # 设置 debug 级别 1:打印 0: 不打印

server.connect(smtp_server) # 连接服务器

server.login(get_val(from_addr)[0], password) # 发件人账号登录

# 发送邮件

if cc_addr is not None:

server.sendmail(get_val(from_addr)[0],

get_val(to_addr) + get_val(cc_addr),

msg.as_string())

else:

server.sendmail(get_val(from_addr)[0], get_val(to_addr),

msg.as_string())

server.quit() # 退出

def get_val(dic):

"""字典取值,返回列表"""

val = list(dic.values())

return val

def _format_addr(dic):

"""规范地址格式处理, 支持多个收件人"""

addr_list = []

for name, addr in dic.items():

addr_list.append(formataddr((Header(name, 'utf-8').encode(), addr)))

return ','.join(addr_list)

def files(msg, file_path):

"""

msg : object

邮件主体容器

file_path : str or list

附件的文件路径

"""

if isinstance(file_path, str):

file_path = [file_path]

for path in file_path:

# 添加附件就是加上一个MIMEBase,从本地读取一个文件:

with open(path, 'rb') as f:

# 创建收纳附件的容器 mime

mime = MIMEBase('application', 'octet-stream')

# 构造附件

basename = os.path.basename(path) # 注意:此时 basename 为 utf-8 编码

# 加上必要的头信息

# basename 转码 gbk, 否则附件带有中文名会有乱码

mime.add_header('Content-Disposition', 'attachment',

filename=('gbk', '', basename))

mime.add_header('Content-ID', '<0>')

mime.add_header('X-Attachment-Id', '0')

mime.set_payload(f.read()) # 把附件的内容读进 mime

encoders.encode_base64(mime) # 用Base64编码

msg.attach(mime) # 添加到 MIMEMultipart 中

return msg

if __name__ == "__main__":

from_addr = {'我是发件人': '123456789@example.com'} # 发送人昵称和地址

to_addr = {'收件人1': '223344@example.com', '收件人2': '987654@example.com'} # 收件人昵称地址

mailhost = ('smtp.exmail.qq.com', 465)

password = 'mypassword'

msg_subject = '我是邮件标题'

exc_msg = '我是邮件正文内容'

file_path = ["测试附件1.xlsx", "测试附件2.xlsx"]

send_email(from_addr, to_addr, mailhost, password, msg_subject,

exc_msg, cc_addr=cc_addr, file_path=file_path)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值