SMTP 配置教程:从零开始搭建邮件发送系统

SMTP(Simple Mail Transfer Protocol)是互联网上发送邮件的标准协议。无论是网站注册验证、密码重置还是订单通知,背后都是 SMTP 在工作。本文介绍两种邮件发送方案:使用第三方邮件服务(推荐)和自建邮件服务器。

一、SMTP 基础

1.1 SMTP 工作原理

发件人 → MUA(邮件客户端)
         ↓ SMTP
       MTA(邮件传输代理)
         ↓ SMTP
       MTA(接收方)
         ↓ POP3/IMAP
       MUA → 收件人
  • MUA(Mail User Agent):邮件客户端(Outlook、Thunderbird)
  • MTA(Mail Transfer Agent):邮件传输代理(Postfix、Sendmail)
  • MDA(Mail Delivery Agent):邮件投递代理

1.2 SMTP 端口

端口 加密方式 说明
25 无/STARTTLS 传统端口,很多 ISP 已屏蔽
465 SSL/TLS SMTPS,推荐使用
587 STARTTLS 提交端口,推荐使用
2525 非标准 部分服务商提供的备用端口

建议使用 587(STARTTLS)或 465(SSL)端口发送邮件,25 端口常被 ISP 和云服务商屏蔽。

二、使用第三方邮件服务(推荐)

大多数应用不需要自建邮件服务器,使用第三方服务更简单、可靠。

2.1 通用 SMTP 配置

// PHP PHPMailer 示例
use PHPMailer\PHPMailer\PHPMailer;

$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host       = 'smtp.sendgrid.net';     // SMTP 服务器
$mail->SMTPAuth   = true;
$mail->Username   = 'apikey';                // 用户名(SendGrid 固定为 apikey)
$mail->Password   = 'SG.xxxxx';              // API Key
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port       = 587;

$mail->setFrom('[email protected]', 'Your App');
$mail->addAddress('[email protected]');
$mail->Subject = '验证您的邮箱';
$mail->Body    = '请点击链接验证您的邮箱地址:https://...';
$mail->send();

2.2 各服务商 SMTP 配置

# Python smtplib 示例 - SendGrid
import smtplib
from email.mime.text import MIMEText

msg = MIMEText('邮件内容')
msg['Subject'] = '测试邮件'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'

with smtplib.SMTP('smtp.sendgrid.net', 587) as server:
    server.starttls()
    server.login('apikey', 'SG.xxxxx')
    server.send_message(msg)

各服务商 SMTP 参数:

服务商 服务器 端口 认证方式
SendGrid smtp.sendgrid.net 587/465 API Key
Mailgun smtp.mailgun.org 587/465 登录名+密码
Resend smtp.resend.com 587/465 API Key
Amazon SES email-smtp.region.amazonaws.com 587/465 SMTP 凭证
Mailjet in-v3.mailjet.com 587/465 API Key

2.3 应用程序框架配置

// Node.js + Nodemailer
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: 'smtp.sendgrid.net',
  port: 587,
  auth: {
    user: 'apikey',
    pass: process.env.SENDGRID_API_KEY,
  },
});

await transporter.sendMail({
  from: '"App Name" <[email protected]>',
  to: '[email protected]',
  subject: '密码重置',
  html: `<p>请点击链接重置密码:<a href="${resetLink}">重置密码</a></p>`,
});
// Laravel 配置 (.env)
MAIL_MAILER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=SG.xxxxx
MAIL_ENCRYPTION=tls
[email protected]
MAIL_FROM_NAME="${APP_NAME}"

三、自建邮件服务器(高级)

3.1 使用 Postfix + Dovecot

适用于需要完全控制邮件系统的场景:

# Ubuntu 安装 Postfix
apt update && apt install postfix dovecot-core dovecot-imapd

# 配置 Postfix
postconf -e 'myhostname = mail.yourdomain.com'
postconf -e 'mydomain = yourdomain.com'
postconf -e 'myorigin = $mydomain'
postconf -e 'inet_interfaces = all'
postconf -e 'mynetworks = 127.0.0.0/8'
postconf -e 'smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem'
postconf -e 'smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key'
postconf -e 'smtpd_use_tls = yes'

# 重启服务
systemctl restart postfix
systemctl restart dovecot

3.2 自建 vs 第三方

维度 自建邮件服务器 第三方邮件服务
成本 仅服务器费用 按量或包月
送达率 较低(需预热 IP) 高(共享 IP 池信誉好)
控制权 完全控制 受限于服务商
维护成本 高(需监控、防攻击) 低(服务商维护)
可扩展性 需自行扩展 自动扩展
隐私 数据在自己服务器 数据在第三方

结论:除非有特殊需求(数据合规、极大量邮件),否则建议使用第三方邮件服务。

四、邮件发送最佳实践

4.1 发送限制

服务商 每日上限 每秒上限
SendGrid 免费版 100 封 10 封
SendGrid Essentials 50,000 封 根据套餐
Mailgun Foundation 50,000 封 根据套餐
自建服务器 取决于服务器 需自行控制

4.2 错误处理

// 邮件发送错误处理
async function sendEmailWithRetry(emailData, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const result = await transporter.sendMail(emailData);
      return result;
    } catch (error) {
      if (attempt === maxRetries) throw error;
      
      // 指数退避
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
      console.log(`重试第 ${attempt} 次...`);
    }
  }
}

4.3 队列处理

对于大量邮件,使用消息队列异步发送:

// 使用 Bull 队列处理邮件
const Queue = require('bull');
const emailQueue = new Queue('email', redisConfig);

// 添加任务
emailQueue.add({
  to: '[email protected]',
  subject: '验证您的邮箱',
  html: '<p>请点击链接验证...</p>',
});

// 处理任务
emailQueue.process(async (job) => {
  await transporter.sendMail(job.data);
});

五、常见问题排查

问题 可能原因 解决方案
连接超时 SMTP 端口被防火墙/ISP 屏蔽 尝试使用 587 或 465 端口
认证失败 API Key 或密码错误 检查 API Key 权限
被拒收(550) IP 信誉低或未配置 SPF/DKIM 配置邮件认证,预热 IP
进入垃圾箱 内容或信誉问题 优化内容,检查发送频率
发送速率限制 超出服务商限制 使用队列控制发送速率

六、总结

对于大多数应用,推荐使用第三方邮件服务(SendGrid/Mailgun/Resend)的 SMTP,既简单又可靠。只需配置好 SPF/DKIM/DMARC 认证,就能获得良好的送达率。自建邮件服务器只适合有特殊需求(数据合规、每月百万级邮件量)的场景。无论使用哪种方案,邮件发送队列、错误处理和监控都是必须的组成部分。