通过 SMTP 发送会议邀请(含日历附件)

更新时间:
复制为 MD 格式

1. 概述

本方案使用 Python 脚本通过 SMTP 协议发送带有 .ics 日历附件的会议邀请邮件。收件人可在 Outlook、Gmail、Apple Calendar 等客户端中直接点击“接受/拒绝”,自动将事件加入日历。

2. Python 示例代码

安装以下 Python 包:

pip install icalendar pytz
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from icalendar import Calendar, Event
from datetime import datetime
import pytz
import uuid

# === 配置区(请用户自行填写)===
SMTP_SERVER = "smtpdm.aliyun.com"
SMTP_PORT = 465  # SSL 端口
SENDER_EMAIL = "your_email@example.com"        # 发件人邮箱
SENDER_PASSWORD = "your_app_password"          # SMTP 授权码(非登录密码)
RECIPIENT_EMAIL = "recipient@example.com"      # 收件人邮箱

# === 创建 iCalendar 事件 ===
cal = Calendar()
cal.add('prodid', '-//Your Organization//Meeting Calendar//EN')
cal.add('version', '2.0')

event = Event()
event.add('summary', "团队周会")
event.add('dtstart', datetime(2026, 3, 11, 15, 0, 0, tzinfo=pytz.timezone('Asia/Shanghai')))
event.add('dtend', datetime(2026, 3, 11, 16, 0, 0, tzinfo=pytz.timezone('Asia/Shanghai')))
event.add('dtstamp', datetime.now(pytz.utc))
event.add('description', "讨论项目进度与下周计划")
event.add('location', "线上会议室 / B301")
event.add('uid', str(uuid.uuid4()) + '@yourdomain.example')
event.add('organizer', f'mailto:{SENDER_EMAIL}')
cal.add_component(event)

ical_data = cal.to_ical()

# === 构建邮件(HTML 正文)===
msg = MIMEMultipart()
msg['From'] = SENDER_EMAIL
msg['To'] = RECIPIENT_EMAIL
msg['Subject'] = '会议邀请:团队周会'

#  HTML 格式的邮件正文
html_body = """
<html>
  <head></head>
  <body>
    <h2>会议邀请</h2>
    <p>您好!</p>
    <p>诚邀您参加以下会议:</p>
    <ul>
      <li><strong>主题:</strong>团队周会</li>
      <li><strong>时间:</strong>2026年3月11日(周二)15:00 - 16:00(北京时间)</li>
      <li><strong>地点:</strong>线上会议室 / B301</li>
    </ul>
    <p>请查收附件中的日历邀请,并点击“接受”以确认出席。</p>
    <hr>
    <p style="color: #888; font-size: 0.9em;">
      此邮件由系统自动发送,请勿直接回复。
    </p>
  </body>
</html>
"""

# 将 HTML 正文附加到邮件
msg.attach(MIMEText(html_body, 'html'))  # ← 关键:使用 'html' 而非 'plain'

# 添加 iCalendar 附件(method=REQUEST 触发日历操作)
part = MIMEApplication(ical_data, _subtype='calendar')
part.add_header('Content-Disposition', 'attachment; filename="meeting_invite.ics"')
part.add_header('Content-Type', 'text/calendar; charset=UTF-8; method=REQUEST')
msg.attach(part)

# === 通过 SSL 发送邮件 ===
try:
    with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server:
        server.set_debuglevel(0)  # 生产环境建议关闭调试
        server.login(SENDER_EMAIL, SENDER_PASSWORD)
        server.sendmail(SENDER_EMAIL, RECIPIENT_EMAIL, msg.as_string())
    print("会议邀请(含 HTML 正文)已成功发送!")
except Exception as e:
    print(f"发送失败: {e}")

3. 关键配置说明

配置项

说明

SMTP_SERVER

邮件服务商的 SMTP 地址

SMTP_PORT

必须使用 465(SSL),避免明文传输密码

SENDER_EMAIL

发件人邮箱(需已在邮件服务商处验证)

SENDER_PASSWORD

SMTP 授权码(在邮件控制台生成)

RECIPIENT_EMAIL

收件人邮箱

4. 日历事件字段说明

  • summary:会议标题

  • dtstart / dtend:开始/结束时间(务必指定时区,推荐 Asia/Shanghai

  • uid:全局唯一 ID(格式:uuid@yourdomain,确保唯一性)

  • organizer:组织者邮箱

  • method=REQUEST必须设置,否则客户端不会显示操作按钮

5. 效果展示

邮件:

image

日历:

image

5. 常见问题

Q1: 收件人看不到“接受/拒绝”按钮?

  • 确保邮件头包含:Content-Type: text/calendar; method=REQUEST

  • uid 必须全局唯一且含域名

  • 避免使用别名(如 xxx+tag@example.com)作为 organizer

Q2: SMTP 连接失败?

Q3: 时间显示错误?

  • 所有 datetime 对象必须带时区(使用 pytz.timezone('Asia/Shanghai')

  • 避免混合使用 datetime.utcnow() 和本地时间