smtplib使用.join拼接多收件人时仅首个地址收信问题咨询
问题根因
只有第一个收件人能收到邮件的核心原因是sendmail方法参数传错,另外代码里还有两处冗余和小bug:
smtplib的sendmail()方法第二个参数(实际投递收件人列表)要求传入可迭代的地址列表/元组对象,你现在传的是用,.join()拼接出来的单个字符串,SMTP服务器解析这个参数时只会识别第一个有效邮箱地址,剩余地址会被直接忽略,自然无法收信。注意:给
message['To']赋值的逗号拼接字符串只是邮件头里展示给收件人看的内容,和SMTP协议层面的实际投递列表是两个独立逻辑,不能混为一谈。- 代码冗余创建了两次SMTP连接:先建了587端口的STARTTLS连接做了登录,后面发信时又重新建了465端口的SSL连接,前面的连接完全没被使用,属于无效代码。
- 附件的
Content-Disposition头末尾少了闭合双引号,部分邮件客户端会无法正常识别附件。
修复后代码
直接替换原有代码即可正常给所有收件人发信:
MY_ADDRESS = "*****@gmail.com" # 替换为你的发件人邮箱 MY_PASSWORD = "*****" # 替换为你的邮箱授权码/密码 RECIPIENT_ADDRESS = ['*****@gmail.com', '*****@gmail.com'] # 替换为收件人列表 HOST_ADDRESS = 'smtp.gmail.com' HOST_PORT = 465 # SSL连接直接用465端口即可,不需要额外走587的STARTTLS逻辑 import smtplib from email.utils import formataddr from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication from email.mime.text import MIMEText # 建立服务连接,用with语句自动处理连接关闭 with smtplib.SMTP_SSL(host=HOST_ADDRESS, port=HOST_PORT) as smtp_obj: smtp_obj.login(MY_ADDRESS, MY_PASSWORD) # 创建邮件对象 message = MIMEMultipart() # 配置邮件头 message['From'] = formataddr(('Management', MY_ADDRESS)) message['To'] = ", ".join(RECIPIENT_ADDRESS) # 这里的拼接仅用于邮件头展示 message['Subject'] = "Test Bill - July" # 构造邮件正文 textPart = MIMEText("Hello John & Johnny,\n\nAttached below is your rent bill for the month of July 2022. To receive your rent bill with a physical copy please email back requesting for us to do so. Otherwise, you will receive your rent bill through email. If you pay online and have scheduled a payment then just double check that the amount paid covers the amount due in the bill you receive.\n\nBest,\ Management", 'plain') # 构造附件 filename = "Test Bill - John.pdf" filePart = MIMEApplication(open(filename,"rb").read(),Name=filename) filePart["Content-Disposition"] = f'attachment; filename="{filename}"' # 补全闭合引号 # 组装邮件内容 message.attach(textPart) message.attach(filePart) # 发信:第二个参数直接传原始收件人列表,不要传拼接后的字符串 smtp_obj.sendmail(message['From'], RECIPIENT_ADDRESS, message.as_string())
关键修改点说明
- 删掉了原来无用的587端口冗余连接,统一用上下文管理器处理465端口的SSL连接,不需要手动调用
quit()关闭连接 sendmail的第二个参数直接传入原始的RECIPIENT_ADDRESS列表,保证SMTP服务能识别所有待投递收件人- 补全了附件头的闭合引号,避免部分客户端无法识别附件
- 发件人地址直接复用预定义的
MY_ADDRESS变量,减少重复硬编码
内容的提问来源于stack exchange,提问作者ohmygodimpregnant
相关产品推荐
相关产品推荐

