登录
首页 >  文章 >  python教程

PythonSMTP发邮件实战教程

时间:2025-08-16 18:39:42 210浏览 收藏

想要掌握Python邮件发送?本文为你提供一份详尽的实战教程,深入解析如何使用Python的smtplib和email模块,轻松实现邮件发送功能。我们不仅会教你如何处理邮件内容的编码问题,避免乱码,还会详细讲解如何添加附件,让你的邮件更加丰富多彩。此外,本文还总结了常见的邮件发送失败原因,例如认证失败、连接失败以及收件人被拒绝等,并提供相应的排查建议和解决方案。通过本文,你将学会如何构建稳定可靠的Python邮件发送系统,或者你还可以选择使用更高级的第三方邮件发送服务提供商的API,它们提供了更高级、更稳定的邮件发送解决方案,例如SendGrid、Mailgun、AWS SES (Simple Mail Service)、阿里云邮件推送等。

Python发送邮件时处理编码和附件需使用email模块。1. 对于文本或HTML内容,使用MIMEText类并指定字符集(如utf-8),确保正确编码避免乱码;2. 附件处理需构建MIMEMultipart容器,每个附件作为MIMEBase对象,经Base64编码并添加Content-Disposition头指定文件名。常见发送失败原因包括:1. 认证失败,需使用授权码而非登录密码,并确认SMTP服务已开启;2. 连接失败,检查服务器地址、端口及网络状况,确保SSL/TLS配置正确;3. 收件人被拒绝,确认收件地址有效且未被服务器拦截。此外,可通过开启调试模式、手动测试及查看异常信息辅助排查问题。

Python如何发送邮件?SMTP协议实战教程

Python发送邮件主要依赖其内置的smtplibemail模块。smtplib负责实际的SMTP(Simple Mail Transfer Protocol)连接和邮件发送,而email模块则帮助我们构建符合MIME标准的邮件内容,比如添加附件、设置HTML格式等。这套组合拳用起来效率很高,但要真正做到稳定可靠地发送,有些坑点是需要提前了解的。

Python如何发送邮件?SMTP协议实战教程

解决方案

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import os

def send_email_via_smtp(sender_email, sender_password, receiver_email, subject, body, smtp_server, smtp_port, is_html=False, attachments=None):
    """
    通过SMTP协议发送邮件。

    Args:
        sender_email (str): 发件人邮箱地址。
        sender_password (str): 发件人邮箱密码或授权码。
        receiver_email (str): 收件人邮箱地址。
        subject (str): 邮件主题。
        body (str): 邮件正文。
        smtp_server (str): SMTP服务器地址。
        smtp_port (int): SMTP服务器端口(通常是465或587)。
        is_html (bool): 正文是否为HTML格式。
        attachments (list): 附件文件路径列表。
    """
    try:
        # 构建邮件内容
        if attachments:
            msg = MIMEMultipart()
        else:
            msg = MIMEText(body, 'html' if is_html else 'plain', 'utf-8')

        msg['From'] = sender_email
        msg['To'] = receiver_email
        msg['Subject'] = subject

        if attachments:
            msg.attach(MIMEText(body, 'html' if is_html else 'plain', 'utf-8'))
            for filepath in attachments:
                if not os.path.exists(filepath):
                    print(f"警告:附件文件不存在 - {filepath}")
                    continue
                part = MIMEBase('application', 'octet-stream')
                with open(filepath, 'rb') as file:
                    part.set_payload(file.read())
                encoders.encode_base64(part)
                part.add_header('Content-Disposition', f'attachment; filename="{os.path.basename(filepath)}"')
                msg.attach(part)

        # 连接SMTP服务器并发送邮件
        print(f"尝试连接SMTP服务器: {smtp_server}:{smtp_port}")
        server = None
        if smtp_port == 465: # SSL加密
            server = smtplib.SMTP_SSL(smtp_server, smtp_port)
        elif smtp_port == 587: # TLS加密
            server = smtplib.SMTP(smtp_server, smtp_port)
            server.starttls() # 启动TLS加密
        else:
            raise ValueError("不支持的SMTP端口,请使用465 (SSL) 或 587 (TLS)。")

        # server.set_debuglevel(1) # 调试模式,会打印详细的SMTP交互日志
        server.login(sender_email, sender_password)
        server.sendmail(sender_email, receiver_email, msg.as_string())
        server.quit()
        print("邮件发送成功!")

    except smtplib.SMTPAuthenticationError as e:
        print(f"SMTP认证失败:请检查邮箱地址或授权码是否正确。错误信息:{e}")
        print("提示:部分邮箱服务(如QQ、163)需要开启SMTP服务并使用授权码而非登录密码。")
    except smtplib.SMTPConnectError as e:
        print(f"SMTP连接失败:请检查SMTP服务器地址和端口是否正确,或网络是否存在问题。错误信息:{e}")
    except smtplib.SMTPRecipientsRefused as e:
        print(f"收件人被拒绝:可能收件人地址无效或服务器拒绝接收。错误信息:{e.recipients}")
    except Exception as e:
        print(f"发送邮件时发生未知错误:{e}")

# 示例用法 (请替换为您的实际信息)
if __name__ == "__main__":
    SENDER_EMAIL = "your_email@example.com"  # 你的邮箱
    SENDER_PASSWORD = "your_email_password_or_app_password" # 你的邮箱密码或授权码
    RECEIVER_EMAIL = "recipient_email@example.com" # 收件人邮箱
    SMTP_SERVER = "smtp.example.com" # 邮箱服务商的SMTP服务器地址,例如 'smtp.qq.com', 'smtp.163.com', 'smtp.gmail.com'
    SMTP_PORT = 465 # 或 587

    # 简单文本邮件
    print("\n--- 发送纯文本邮件 ---")
    send_email_via_smtp(
        sender_email=SENDER_EMAIL,
        sender_password=SENDER_PASSWORD,
        receiver_email=RECEIVER_EMAIL,
        subject="Python SMTP测试邮件 - 纯文本",
        body="这是一封由Python脚本发送的纯文本测试邮件。",
        smtp_server=SMTP_SERVER,
        smtp_port=SMTP_PORT
    )

    # HTML格式邮件
    print("\n--- 发送HTML格式邮件 ---")
    html_body = """
    
    
        

你好,

这是一封HTML格式的测试邮件,由Python脚本发送。

你可以尝试点击这个链接:Python官网

Python Logo

祝好!

""" send_email_via_smtp( sender_email=SENDER_EMAIL, sender_password=SENDER_PASSWORD, receiver_email=RECEIVER_EMAIL, subject="Python SMTP测试邮件 - HTML格式", body=html_body, smtp_server=SMTP_SERVER, smtp_port=SMTP_PORT, is_html=True ) # 带有附件的邮件 (请确保有这些文件在当前目录下,或者提供完整路径) # 比如创建一个名为 'test.txt' 和 'image.png' 的文件 # with open('test.txt', 'w') as f: # f.write("这是一个附件测试文件。") # from PIL import Image # img = Image.new('RGB', (60, 30), color = 'red') # img.save('image.png') print("\n--- 发送带附件的邮件 ---") # 假设 'test.txt' 和 'image.png' 存在于脚本同目录下 # 实际使用时,请替换为真实文件路径 test_attachments = ['test.txt', 'image.png'] # 确保这些文件存在 send_email_via_smtp( sender_email=SENDER_EMAIL, sender_password=SENDER_PASSWORD, receiver_email=RECEIVER_EMAIL, subject="Python SMTP测试邮件 - 带附件", body="这是一封带有附件的测试邮件,请查收!", smtp_server=SMTP_SERVER, smtp_port=SMTP_PORT, attachments=test_attachments )

如何处理邮件内容编码和附件?

说实话,邮件内容编码和附件这块,初次接触时确实会觉得有点绕,因为这涉及到MIME(Multipurpose Internet Mail Extensions)标准。简单来说,邮件不仅仅是纯文本,它可能包含各种字符集、HTML格式、图片、文档等等,MIME就是一套规则,告诉邮件客户端如何正确解析这些复杂的内容。

email模块就是Python实现MIME标准的利器。对于纯文本或HTML,我们用MIMEText类,它会自动处理编码问题,比如你指定'utf-8',它就会在邮件头里加上Content-Type: text/plain; charset="utf-8"或者text/html; charset="utf-8"。这很关键,否则收件人看到的可能就是乱码。

Python如何发送邮件?SMTP协议实战教程

而附件,那更是MIME的拿手好戏。它需要将邮件拆分成多个“部分”(Part),用MIMEMultipart来做这个容器。每个附件都是一个独立的MIMEBase对象。比如,你要发一个PDF,你就得读取PDF文件的二进制内容,然后用encoders.encode_base64进行Base64编码(因为邮件传输协议通常是基于文本的,二进制数据需要转换),最后加上Content-Disposition头,告诉收件箱“这是一个附件,它的原始文件名是什么”。代码里我已经把这个逻辑封装进去了,MIMEMultipart作为主容器,邮件正文和各个附件都是它的子部分。这样做,收件方就能清晰地看到邮件内容和可下载的附件了。

为什么我的邮件发送失败了?常见问题与排查

这大概是大家用Python发邮件最常遇到的问题了,我个人也踩过不少坑。遇到发送失败,别急着怀疑人生,通常是以下几个原因:

Python如何发送邮件?SMTP协议实战教程
  1. 认证失败 (SMTPAuthenticationError)

    • 密码错误? 检查你输入的密码是否正确。
    • 授权码? 很多邮箱服务商(比如QQ邮箱、163邮箱、Gmail等)出于安全考虑,不再允许直接使用登录密码进行SMTP认证,而是需要你登录网页版邮箱,在设置里开启SMTP服务,然后生成一个“授权码”或“客户端专用密码”。这个授权码才是你在Python脚本里需要使用的密码。这个是最常见的坑,没有之一。
    • 账户未开启SMTP服务? 同样,需要在邮箱设置里手动开启SMTP服务。
  2. 连接失败 (SMTPConnectError)

    • 服务器地址或端口错误? smtp.example.com这样的地址和465/587这样的端口号,一定要和你的邮箱服务商提供的一致。比如Gmail是smtp.gmail.com,QQ邮箱是smtp.qq.com
    • 网络问题? 检查你的网络连接是否正常,防火墙是否阻止了Python程序访问外部SMTP端口。有时候公司内网会有严格的端口限制。
    • SSL/TLS配置问题? 如果是465端口,通常是直接SSL连接 (SMTP_SSL);如果是587端口,则需要先建立普通连接,再调用starttls()方法升级为TLS加密连接。端口和加密方式不匹配会导致连接失败。
  3. 收件人被拒绝 (SMTPRecipientsRefused)

    • 收件人地址无效? 检查收件人邮箱地址是否拼写错误或不存在。
    • 服务器拒绝? 有时发件服务器会拒绝向某些域名或地址发送邮件,可能是对方服务器的黑名单,或者你的邮件被判定为垃圾邮件特征。

排查建议:

  • 开启调试模式:在smtplib.SMTPsmtplib.SMTP_SSL对象创建后,调用server.set_debuglevel(1)。这会打印出SMTP服务器和客户端之间的详细通信日志,你能清楚看到是哪个环节出了问题,比如认证失败的具体原因码。
  • 手动测试:尝试使用邮件客户端(如Outlook、Thunderbird)配置相同的SMTP服务器、端口、邮箱和密码,看能否正常发送。如果客户端也无法发送,那问题多半出在邮箱设置或网络上。
  • 查看错误信息:Python的异常信息通常很详细,比如SMTPAuthenticationError就明确告诉你认证出了问题。

除了SMTP,还有其他发送邮件的方式吗?

当然有,SMTP是底层协议,但很多时候我们并不需要直接去操作它。想象一下,你造房子不需要从挖矿炼铁开始,直接买钢筋水泥多方便。邮件发送也是类似。

现在非常流行的是使用第三方邮件发送服务提供商的API。这些服务商,比如SendGrid、Mailgun、AWS SES (Simple Email Service)、阿里云邮件推送等,它们提供了更高级、更稳定的邮件发送解决方案。

它们的优势在于:

  1. 简化开发:你不需要关心SMTP的细节,只需要调用它们提供的API(通常是RESTful API),传入发件人、收件人、主题、正文等参数即可。
  2. 高送达率:这些服务商有专业的团队来维护IP信誉,确保你的邮件能顺利进入收件箱,而不是被当成垃圾邮件。这对于批量发送、营销邮件尤其重要。
  3. 统计分析:它们通常提供邮件的发送状态、打开率、点击率、退订率等详细数据,方便你进行后续分析和优化。
  4. 弹性扩展:面对大量的邮件发送需求,这些服务可以轻松扩展,而你自己搭建的SMTP服务器可能很快就会遇到性能瓶颈。
  5. 处理复杂场景:比如邮件模板、批量发送、延时发送、Webhook通知等,这些都是它们服务的亮点。

虽然直接使用SMTP能让你对邮件发送过程有更深的理解和控制,但对于生产环境或有更高要求的场景,我个人更倾向于推荐使用这些专业的第三方服务。它们能让你把精力放在业务逻辑上,而不是邮件发送的各种技术细节和坑点上。

好了,本文到此结束,带大家了解了《PythonSMTP发邮件实战教程》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多文章知识!

相关阅读
更多>
最新阅读
更多>
课程推荐
更多>