背景
小程序 扫码签到工具 需要通过邮箱给用户发送签到二维码与签到详情。小程序每天发送的邮件数在 300 到 500 封左右。在选取邮箱服务商时,我使用了腾讯企业邮箱。由于腾讯的企业邮箱每天允许的邮件上限是 500 封,为了避免因用户暴增导致邮件数达到上限,我创建了3个企业邮箱(不是在一个域名下创建3个邮箱,而是分别使用3个域名创建企业邮箱),让3个邮箱轮换给用户发邮件。
在使用腾讯企业邮箱过程中,当小程序发邮件频率比较高的时候,经常收到提示,需要输入验证码才能发送邮件。次数多了,我就开始犹豫,是否应该考虑其他的方案了,如 SendCloud、Amazon SES、Mailgun、SendGrid,甚至自建邮箱。
周六上午,小程序频繁地出现邮件发送失败的情况,失败信息为 550 Sender frequency limited。我立即分别申请了 sohu、163 邮箱,在发送邮件时,分别轮换这几个邮箱向用户发送邮件,让腾讯邮箱稍作休息。
出现这么严重的问题,是时候考虑其他的解决方案了。
方案
可选方案
有两种解决方案:1. 选用第三方的邮件推送服务;2.自建邮箱服务器。
扫码签到工具 小程序的用户绝大部分在国内,使用 QQ 邮箱的比例超过 50%。
关于方案一,第三方邮件推送服务。基本上可以忽略 Amazon SES、Mailgun、SendGrid,根本用户的反馈来看,xQQ 邮箱基本收不到来自这些服务商的邮件,这样就只剩下 SendCloud 这一个选项了。
至于方案二,如果选择国外的 VPS,一方面担心不经意之间被墙,另一方面连接速度比较慢,只能考虑国内的 VPS。至于国内的 VPS,最大的两家阿里与腾讯,都疯掉了 25 端口,这就意味着 VPS 基本行不通。
回到方案一,那就考虑 SendCloud 吧。读了文档之后,粗估还需要不少工作量。考虑到即将上线的另外一个小程序也需要改造,算了,放弃吧。
那退而求其次,考虑国外的 VPS 吧。在正式实施之前,我先拿局域网内的服务器试验性地尝试下。
最终方案
先把内网服务器上与邮件收发相关的端口能对外通信,然后在内网的服务器上安装邮箱服务器即可。当然,最重要的是,必须保证发送出的邮件不会被其他邮箱 (尤其是QQ邮箱) 服务器拒收。
经过权衡,我选择了 Poste,这是一个轻量的免费邮箱服务器。
实施步骤
1. 对外网开放服务器与邮件相关的端口。
我的路由器是小米,先使用路由器的端口转发功能,把邮箱收发相关的端口转发到局域网中的服务器。需要转发的端口包括 25、80、443、110、143、465、587、993、995。
以下是端口转发的部分截图。

由于小米路由器的管理网页占用了80端口,在添加80端口转发之前,需要把它释放出来,可参见这篇文章:小米路由器修改80端口占用。
Poste用到的这几个端口的说明如下:
端口 | 目的 |
---|---|
25 | SMTP – 邮箱服务器接收邮件 |
80 | HTTP – 会重定向到https(但这个端口必须开放,用于安装Let’s Encrypt证书) |
110 | POP3 – 访问邮箱的标准协议,在邮件客户端认证之前需要支持 STARTTLS。 |
143 | IMAP – 访问邮箱的标准协议,在邮件客户端认证之前需要支持 STARTTLS。 |
443 | HTTPS – 通过 Web 网页访问管理页面与邮件客户端页面。 |
465 | SMTPS – 较老的SMTPs 端口。 |
587 | MSA – 在STARTTLS与认证之后,邮箱客户端通信的 SMTP 端口。 |
993 | IMAPS – 加密的 IMAP 端口 |
995 | POP3S – 加密的 POP3 端口。 |
2. 配置 DNS。
配置 DNS 完全按照参见官方文档 Configuring DNS, 不赘述。
3. 安装 Poste。
1) 下载Docker Image。打开网页 https://hub.docker.com/r/analogic/poste.io ,运行:
docker pull analogic/poste.io
2) 运行 Docker。当然,在创建之前先应创建目录 /home/ubuntu/poste/data 供 docker 共享。
sudo docker run \ -p 25:25 \ -p 80:80 \ -p 443:443 \ -p 110:110 \ -p 143:143 \ -p 465:465 \ -p 587:587 \ -p 993:993 \ -p 995:995 \ -v /etc/localtime:/etc/localtime:ro \ -v /home/ubuntu/poste/data:/data \ --name "posteServer" \ -h "mail.xxx.cn" \ -t analogic/poste.io
运行完成之后,就可以打开首页 http://mail.xxx.cn 了。
4. 配置 Poste。
在打开首页 http://mail.xxx.cn 时,它会自动重定向到 https://mail.xxx.cn。
先配置登录名,之后登录。
在 Vitrual Domains 里,点击域名,然后生成 DKIM 记录,把它填到 DNS 记录中。

然后点击 Server Settings,选择 TLS Certificate 页,在此页面生成 SSL 证书,此证书由 Let’s Encrypt 颁发。在生成证书过程中,会现在服务器上创建一个文件,然后尝试通过 http 请求访问它,以此验证此域名的归属。由于此 http 请求的端口是 80,所以在创建过程中,必须确保 80 端口开放。
当然,如果有现成的证书可用,不必保证 80 端口可用。
试用
配置完毕之后,等 2 个小时之后再试用吧。2个小时不是必须的,是为了确保 DNS 在配置之后有足够的时间在全球生效。
在内网给自己发邮件,发送成功,接收成功。
分别在内网、外网,发送邮件给 hotmail、gmail、qq。hotmail、qq能收到,不过 hotmail 的邮件进了垃圾箱,gmail收不到一封邮件。但是,我在服务器上运行 wget https://www.google.com,能够获取 google 的首页内容。至于为什么发送给 Gmail 的邮件全收不到,原因未知。
先通过 hotmail 、qq、gmail 向邮箱服务器发邮件,可以收到。
可是,当我使用 Laravel 自带邮件代码以 SMTP 协议连上邮件服务器给 QQ 发邮件时,直接收到 550 Mail content denied 的退信。于是,我尝试先通过 QQ 邮箱给服务器发邮件,然后在服务器的web网页上回复邮件,增加邮箱的可信度。再发邮件就没问题了。
总结
到此为止,Poste 创建的邮箱服务器就可以工作,用来作为邮件服务器为小程序发送邮件了。毕竟是自己家里的服务器,为了保证万一服务器宕机时仍旧能正常发邮件,在系统中,我加进了一段代码,确保邮箱服务器宕掉时,系统立即切换到腾讯邮箱。
后续计划
下一步,申请国外的 VPS, 代替这台局域网内的邮箱服务器。发邮件的速度可能会慢些,但能保证全球都能收到邮件。与此同时,即将发布的小程序还能共享这台邮箱服务器。
请你留言