Python3 SMTP发送邮件(保姆级教程)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在数字化时代,自动化发送邮件是开发者的必备技能之一。无论是电商订单通知、系统告警,还是定期报告生成,SMTP(Simple Mail Transfer Protocol)技术都能高效完成任务。本文将从零开始,逐步讲解如何使用Python3实现SMTP邮件发送功能,帮助编程初学者和中级开发者掌握这一实用技能。


SMTP协议的基础概念

SMTP(简单邮件传输协议)是互联网电子邮件系统的核心协议之一,它负责在邮件服务器之间或客户端与服务器之间传递邮件。可以将其比喻为“邮件快递公司”:当用户通过客户端(如Outlook或Python脚本)编写邮件后,SMTP协议会像快递员一样,将邮件从发件人的服务器“打包”并“投递”到收件人的服务器中。

SMTP的工作流程包含三个关键步骤:

  1. 连接服务器:客户端与SMTP服务器建立TCP连接(通常使用端口25、465或587)。
  2. 身份验证:用户通过用户名和密码(或令牌)向服务器证明身份。
  3. 发送邮件:将邮件内容按照特定格式(如RFC 5322标准)传输至目标服务器。

环境准备与核心库介绍

Python中实现SMTP功能的核心库是smtpdsmtplib。其中,smtplib提供了与SMTP协议交互的接口,而email模块用于构建邮件内容。

安装与导入

无需额外安装,Python3标准库已包含这些模块:

import smtplib  
from email.mime.text import MIMEText  
from email.mime.multipart import MIMEMultipart  

邮件服务器配置

不同邮件服务商的SMTP设置不同,常见配置如下:

邮箱服务商SMTP服务器地址端口(SSL)端口(TLS)
Gmailsmtp.gmail.com465587
Outlooksmtp.office365.com587587
163邮箱smtp.163.com46525/994

注意:使用前需确保邮箱已开启SMTP服务。例如,Gmail用户需在账户安全设置中允许“不够安全的应用”访问。


第一步:发送纯文本邮件

以下代码演示了如何通过Gmail发送最基础的纯文本邮件:

def send_simple_email(subject, body, to_email):  
    # 邮箱配置  
    smtp_server = "smtp.gmail.com"  
    smtp_port = 587  # TLS加密端口  
    from_email = "your-email@gmail.com"  
    password = "your-password"  

    # 构建邮件内容  
    message = MIMEText(body)  
    message["Subject"] = subject  
    message["From"] = from_email  
    message["To"] = to_email  

    # 连接并发送  
    with smtplib.SMTP(smtp_server, smtp_port) as server:  
        server.starttls()  # 启用TLS加密  
        server.login(from_email, password)  
        server.sendmail(  
            from_addr=from_email,  
            to_addrs=to_email,  
            msg=message.as_string()  
        )  

send_simple_email(  
    subject="测试邮件",  
    body="这是一封测试邮件,由Python发送!",  
    to_email="recipient@example.com"  
)  

关键步骤解析

  1. MIMEText:将文本内容封装为符合邮件规范的MIME格式。
  2. starttls():在建立连接后启用TLS加密,确保传输过程的安全性。
  3. sendmail():接收发件人、收件人和邮件内容字符串,完成实际传输。

进阶功能:发送带附件的HTML邮件

实际应用中,邮件常包含HTML格式的内容或附件。以下示例演示如何发送包含图片和PDF文件的复杂邮件:

def send_complex_email(subject, html_body, to_email, attachments=None):  
    smtp_server = "smtp.gmail.com"  
    smtp_port = 587  
    from_email = "your-email@gmail.com"  
    password = "your-password"  

    # 创建复合消息对象  
    message = MIMEMultipart()  
    message["Subject"] = subject  
    message["From"] = from_email  
    message["To"] = to_email  

    # 添加HTML正文  
    html_part = MIMEText(html_body, "html")  
    message.attach(html_part)  

    # 添加附件(可选)  
    if attachments:  
        for file_path in attachments:  
            with open(file_path, "rb") as f:  
                part = MIMEText(f.read(), "base64", "utf-8")  
                part["Content-Type"] = "application/octet-stream"  
                part.add_header(  
                    "Content-Disposition",  
                    "attachment",  
                    filename=file_path.split("/")[-1]  
                )  
                message.attach(part)  

    # 发送逻辑与之前相同  
    with smtplib.SMTP(smtp_server, smtp_port) as server:  
        server.starttls()  
        server.login(from_email, password)  
        server.sendmail(  
            from_email,  
            to_email,  
            message.as_string()  
        )  

send_complex_email(  
    subject="带附件的邮件",  
    html_body="<h1>这是HTML内容</h1><img src='cid:image1'>",  
    to_email="recipient@example.com",  
    attachments=["report.pdf", "screenshot.png"]  
)  

扩展点说明

  • MIMEMultipart:用于组合多个邮件部分(文本、附件等)。
  • Content-Disposition:指定附件的名称和类型。
  • CID引用图片:若需内联图片,可通过cid:图片ID在HTML中引用。

异常处理与安全性优化

在实际开发中,需考虑以下常见问题:

异常处理

SMTP发送过程中可能因网络波动、认证失败或邮件内容错误引发异常。使用try-except块捕获并处理这些情况:

try:  
    server.sendmail(...)  
except smtplib.SMTPAuthenticationError:  
    print("认证失败,请检查邮箱密码或SMTP权限")  
except smtplib.SMTPException as e:  
    print(f"发送失败:{str(e)}")  
except Exception as e:  
    print(f"未知错误:{str(e)}")  

安全性优化建议

  1. 避免明文密码:使用环境变量或加密配置文件存储敏感信息。
  2. 使用环境变量示例
    import os  
    password = os.getenv("SMTP_PASSWORD")  
    
  3. 双重认证(2FA):若邮箱启用了2FA,需生成并使用“应用专用密码”。

实战案例:自动化订单通知系统

假设我们需要为电商平台开发一个订单通知功能,当用户下单后自动发送确认邮件。代码逻辑如下:

def send_order_confirmation(order_id, customer_email):  
    subject = "订单确认通知"  
    html_body = f"""  
    <p>尊敬的客户:</p>  
    <p>您的订单#{order_id}已成功提交!</p>  
    <p>预计将在3个工作日内发货。</p>  
    """  
    send_complex_email(  
        subject=subject,  
        html_body=html_body,  
        to_email=customer_email  
    )  

优势

  • 可扩展性:可轻松添加物流跟踪链接或退订选项。
  • 模板化:将HTML内容提取为独立模板文件,便于维护。

最佳实践与性能调优

并发发送优化

若需批量发送邮件(如营销活动),单线程逐个发送效率较低。可使用concurrent.futures实现多线程:

from concurrent.futures import ThreadPoolExecutor  

def batch_send_emails(email_list):  
    with ThreadPoolExecutor(max_workers=5) as executor:  
        for email in email_list:  
            executor.submit(send_email, **email_params)  

日志与监控

记录发送状态以排查问题:

import logging  
logging.basicConfig(filename="mail.log", level=logging.INFO)  

def send_email(...):  
    try:  
        # 发送逻辑  
        logging.info(f"邮件发送成功:{to_email}")  
    except Exception as e:  
        logging.error(f"发送失败:{str(e)}")  

结论

通过本文,读者已掌握从基础SMTP原理到复杂邮件功能的实现方法。无论是自动化通知、系统告警还是商业应用,Python3的SMTP模块都能提供强大支持。建议读者结合自身需求,进一步探索以下方向:

  1. 集成邮件模板引擎(如Jinja2)实现动态内容渲染。
  2. 邮件队列系统(如Celery)实现异步发送,提升系统响应速度。
  3. 反垃圾邮件策略(如SPF、DKIM验证)确保邮件送达率。

掌握SMTP发送邮件技术后,开发者可以更灵活地构建智能化、自动化的解决方案,进一步提升开发效率和用户体验。

最新发布