Python 自动化通信:发送邮件与短信

前两篇我们借助 Daoman Python AI 实现了 Excel、Word、PDF 的一键生成——但文件躺在服务器上没人收,等于白干。今天就来打通业务自动化的最后一公里:用 Python 发送邮件和短信,把「文档产出 → 消息触达」这条链路彻底焊死。


1. 发送电子邮件:用 SMTP 直接对话邮件服务器

发邮件不一定要打开浏览器,本质上就是让程序模拟邮件客户端,通过 SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)与网易 / QQ / 企业邮箱服务器握手、加密、投递。Python 内置的 smtplib 已经帮我们封装好了这些底层细节。

1.1 前置安全准备:拿到专属「授权码」

直接用登录密码在第三方程序中登录邮箱风险太高,现在主流邮箱(126、163、QQ、Gmail 等)都要求使用授权码

  1. 登录邮箱网页版
  2. 进入「设置 → 账户 → POP3/IMAP/SMTP/Exchange」
  3. 开启 POP3/SMTP 服务
  4. 按提示绑定手机、验证短信,拿到一串 16 位左右的授权码(只显示一次,务必保存好)

💡 企业邮箱的授权码获取方式大同小异,联系 IT 或查内部文档即可。

1.2 第一封:纯文本邮件快速上手

邮件内容由 email.mime 系列模块拼装而成。纯文本邮件直接用 MIMEText;如果后续要加附件、HTML 正文或图片,就需要用「容器」MIMEMultipart

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

def send_plain_email():
    # 1. 创建邮件容器(即使只发纯文本,也推荐用容器,方便后续扩展)
    msg = MIMEMultipart()
    msg['From'] = 'daoman_ai_demo@126.com'       # 你的发送邮箱
    msg['To'] = 'recipient@example.com'          # 接收邮箱,多个用逗号分隔
    msg['Subject'] = Header('Daoman Python AI 季度报表通知', 'utf-8')  # 避免中文主题乱码

    # 2. 添加纯文本正文
    plain_body = (
        "您好李总,\n\n"
        "您申请的三季度自动化销售报表已通过 Daoman Python AI 生成完成,"
        "如需添加附件或自定义 HTML 请随时沟通。\n\n"
        "此致\n敬礼\n道满科技技术部"
    )
    msg.attach(MIMEText(plain_body, 'plain', 'utf-8'))

    # 3. 连接 SMTP 服务器(推荐 SSL 加密端口 465,非加密 25 端口需提防被封)
    try:
        # 不同邮箱 SMTP 地址不同:126 邮箱为 smtp.126.com,QQ 邮箱为 smtp.qq.com
        smtp_server = smtplib.SMTP_SSL('smtp.126.com', 465)
        smtp_server.login('daoman_ai_demo@126.com', '你的专属授权码')
        smtp_server.sendmail(
            from_addr='daoman_ai_demo@126.com',
            to_addrs=['recipient@example.com'],   # 必须传列表!
            msg=msg.as_string()
        )
        print("✅ 纯文本邮件发送成功!")
    except Exception as e:
        print(f"❌ 发送失败:{str(e)}")
    finally:
        smtp_server.quit()

send_plain_email()

1.3 升级版:带附件 + HTML 排版的邮件

纯文本有点干巴巴的,我们可以加入 HTML 提升视觉效果(表格、加粗、公司 logo 占位等),同时把 AI 生成好的 Excel / PDF / Word 作为附件一起发送。

附件的核心逻辑

附件本质上是二进制文件,而 SMTP 只能传文本,因此需要用 Base64 将二进制编码成字符流。同时,中文文件名可能出现乱码,需要用 email.header 配套方法处理。

import smtplib
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication  # 比纯 MIMEText 更适合处理附件

def send_fancy_email():
    msg = MIMEMultipart()
    msg['From'] = 'daoman_ai_demo@126.com'
    msg['To'] = 'recipient@example.com'
    msg['Subject'] = Header('【重要】三季度销售分析报告', 'utf-8')

    # 1. 添加 HTML 正文(也可以附带纯文本作为备选,防止收件端不支持 HTML)
    html_body = """
    <html>
      <body>
        <p>亲爱的李总,</p>
        <p>您申请的<strong>202X 年三季度华东区销售分析报告</strong>已由 Daoman Python AI 自动生成,包含以下文件:</p>
        <ul>
          <li>原始销售数据汇总.xlsx</li>
          <li>可视化图表分析报告.pdf</li>
          <li>精简版 Word 汇报.docx</li>
        </ul>
        <p>请查收附件,如有问题随时联系技术部!</p>
        <br>
        <p style="color: #888; font-size: 12px;">道满科技技术部 · 自动生成邮件</p>
      </body>
    </html>
    """
    msg.attach(MIMEText(html_body, 'html', 'utf-8'))

    # 2. 批量添加附件(用循环优雅处理)
    attachment_list = [
        {'path': 'resources/202XQ3_销售数据.xlsx', 'name': '202X年三季度华东区销售数据.xlsx'},
        {'path': 'resources/202XQ3_可视化分析.pdf', 'name': '202X年三季度华东区销售分析.pdf'}
    ]

    for att in attachment_list:
        with open(att['path'], 'rb') as f:
            part = MIMEApplication(f.read())
            # 处理中文文件名,兼容 Outlook / 网易 / QQ 邮箱
            part.add_header(
                'Content-Disposition',
                'attachment',
                filename=('utf-8', '', att['name'])
            )
            msg.attach(part)

    # 3. 连接发送(逻辑与纯文本邮件相同)
    try:
        smtp_server = smtplib.SMTP_SSL('smtp.126.com', 465)
        smtp_server.login('daoman_ai_demo@126.com', '你的专属授权码')
        smtp_server.sendmail(
            'daoman_ai_demo@126.com',
            ['recipient@example.com'],
            msg.as_string()
        )
        print("✅ 带附件 + HTML 邮件发送成功!")
    except Exception as e:
        print(f"❌ 发送失败:{str(e)}")
    finally:
        smtp_server.quit()

send_fancy_email()

2. 发送短信:找第三方网关当「中间商」

与邮件有统一的 SMTP 协议不同,短信并没有通用的编程接口——我们总不能自己建个基站。因此需要借助合规的第三方短信服务商(如阿里云、腾讯云、螺丝帽等),通过它们提供的 HTTP API 来下发短信。

2.1 短信发送的标准合规流程

国家对短信业务管控非常严格,没有签名 / 未经许可发送营销短信属于违规行为。正规流程必须走完以下几步:

  1. 注册服务商账号——推荐阿里云、腾讯云等大厂,合规性好、技术支持到位
  2. 实名认证——企业或个人均需提交资料
  3. 申请短信签名——例如 【道满科技】,会出现在短信的开头或结尾,服务商审核标准明确
  4. 申请短信模板——例如 您的验证码是${code},请于5分钟内输入。请勿泄露给他人!,变量使用服务商指定的占位符
  5. 获取 API Key / Secret——相当于调用接口的凭证

2.2 实战代码(以阿里云短信服务为例)

大厂的 API 通常提供官方 SDK,但这里用通用 requests 库演示,方便你迁移到其他服务商。

import requests
import json
from hashlib import sha256
import hmac
import base64
from datetime import datetime
import urllib.parse

def send_aliyun_sms(phone, code):
    """
    发送阿里云短信验证码。
    需提前开通短信服务、申请签名、审核通过模板。
    """
    # 1. 配置项(强烈建议用环境变量存储,不要硬编码!)
    access_key_id = "你的AccessKey ID"
    access_key_secret = "你的AccessKey Secret"
    sign_name = "道满科技"              # 已审核通过的签名
    template_code = "SMS_123456789"     # 已审核通过的模板
    template_param = json.dumps({"code": code})   # 模板变量转 JSON 字符串

    # 2. 阿里云 API 签名算法(可直接复用,官方文档有标准示例)
    def get_signature(params):
        sorted_params = sorted(params.items())
        canonicalized_query = urllib.parse.urlencode(sorted_params)
        string_to_sign = f"GET&%2F&{urllib.parse.quote_plus(canonicalized_query)}"
        key = f"{access_key_secret}&".encode('utf-8')
        message = string_to_sign.encode('utf-8')
        h = hmac.new(key, message, sha256)
        signature = base64.b64encode(h.digest()).decode('utf-8')
        return signature

    # 3. 构建公共请求参数
    common_params = {
        "SignatureMethod": "HMAC-SHA1",
        "SignatureNonce": str(int(datetime.now().timestamp() * 1000000)),
        "SignatureVersion": "1.0",
        "AccessKeyId": access_key_id,
        "Timestamp": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
        "Format": "JSON",
        "Action": "SendSms",
        "Version": "2017-05-25",
        "RegionId": "cn-hangzhou",
        "PhoneNumbers": phone,
        "SignName": sign_name,
        "TemplateCode": template_code,
        "TemplateParam": template_param
    }

    # 4. 生成签名并拼接 URL
    signature = get_signature(common_params)
    common_params['Signature'] = signature
    request_url = f"https://dysmsapi.aliyuncs.com/?{urllib.parse.urlencode(common_params)}"

    # 5. 发起请求
    try:
        resp = requests.get(request_url, timeout=10)
        result = resp.json()
        if result.get("Code") == "OK":
            print(f"✅ 短信下发成功!手机号:{phone}")
            return True
        else:
            print(f"❌ 短信下发失败:{result.get('Message')}")
            return False
    except Exception as e:
        print(f"❌ 网络请求失败:{str(e)}")
        return False

# 测试发送(请替换为真实手机号)
send_aliyun_sms("13800000000", "666888")

3. 避坑指南与安全建议

  1. 🔐 安全第一
    授权码、API Key / Secret 绝对不要硬编码在代码里(尤其别上传到公开仓库)。推荐使用 python-dotenv 读取环境变量,或借助云服务商的密钥管理服务(KMS)。

  2. 📧 邮件防垃圾信小技巧

    • 避免批量发送完全相同的邮件,可以加入个性化内容(如开头称呼)
    • 尽量使用企业邮箱发送,免费邮箱更容易被标记为垃圾邮件
    • 附件控制在 10 MB 以内,大文件建议用云盘链接替代
  3. 📱 短信合规红线

    • 个人实名只能发送验证码、通知类短信,不得发送营销短信
    • 营销短信必须携带「退订回 T」字样
    • 务必配置 IP 白名单调用频率限制,防止接口被盗刷

掌握了邮件与短信的自动化发送,再结合前两篇的文档自动生成,你已经可以用 Daoman Python AI 打造一套完整的「周报 / 月报自动生成 + 自动通知」系统了。快去动手试试吧~