几天前,我开放了人人影视下载站的用户注册功能,并且新用户在注册后需要验证邮箱才能发表评论。开放注册可能会提高用户的活跃度,但是又总有用户发一些不合适的东西,因此有必要提高一点注册门槛。
后端的接口大概在半年前就写好了,我最近才学了一点点 React做好了邮件验证的功能。
如何用发邮件
我用的是riseup来发,基本如下几步:
- 去域名注册商那边添加一个email forward,因为后需要验证
- 去riseup添加一个alias
- 去DNS那边添加一个SPF 记录
v=spf1 include:riseup.net +all
,如果同时还想用email forward,那就添加 include就好了,比如说我的是这样的v=spf1 include:_spf.mx.cloudflare.net include:riseup.net +all
- 用SMTP协议,可以先用mailhog做测试,确定没问题来之后切到riseup,代码大概这样
import smtplib from email.header import Header from email.mime.text import MIMEText from email.utils import formataddr, parseaddr def _format_addr(s): name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr)) def send_mail(to: str, subject: str, body: str): user = "username" password = "password" host = "mail.riseup.net" port = 465 from_addr = "yyets@dmesg.app" msg = MIMEText(body, 'html', 'utf-8') msg['From'] = _format_addr('YYeTs <%s>' % from_addr) msg['To'] = _format_addr(to) msg['Subject'] = Header(subject, 'utf-8').encode() if port == "1025": server = smtplib.SMTP(host, int(port)) else: server = smtplib.SMTP_SSL(host, int(port)) server.login(user, password) server.sendmail(from_addr, [to], msg.as_string()) server.quit() if __name__ == '__main__': send_mail("benny.think@gmail.com", "test subject", "test body")
收到的邮件也比较理想,一般来说不会进spam
问题
前几天做测试的时候一切顺利,上线的时候本来以为没什么大问题,结果今天却收到了一个用户的反馈,说收不到邮件,试了各种邮箱,检查了垃圾箱,也没有收到。
排查问题
加了几条log之后发现在容器中 smtplib.SMTP_SSL 会直接卡住,如果按ctrl + c会收到这样的报错
Traceback(most recent call last): File "", line 1, in File "/YYeTsBot/yyetsweb/utils.py", line 51, in send_mail server = smtplib.SMTP_SSL(host, int(port)) File "/usr/local/lib/python3.10/smtplib.py", line 1050, in __init__ SMTP.__init__(self, host, port, local_hostname, timeout, File "/usr/local/lib/python3.10/smtplib.py", line 255, in __init__ (code, msg)=self.connect(host, port) File "/usr/local/lib/python3.10/smtplib.py", line 341, in connect self.sock=self._get_socket(host, port, self.timeout) File "/usr/local/lib/python3.10/smtplib.py", line 1057, in _get_socket new_socket=self.context.wrap_socket(new_socket, File "/usr/local/lib/python3.10/ssl.py", line 513, in wrap_socket return self.sslsocket_class._create( File "/usr/local/lib/python3.10/ssl.py", line 1071, in _create self.do_handshake() File "/usr/local/lib/python3.10/ssl.py", line 1342, in do_handshake self._sslobj.do_handshake() ssl.SSLZeroReturnError: TLS/SSL connection has been closed(EOF)(_ssl.c: 997)
奇怪哦,那就排除法做几个测试,首先在容器内nc一下看看
/ # nc -v mail.riseup.net 465 mail.riseup.net (198.252.153.21:465) open
通的耶!那容器内连试试?
[root:~]# docker run --rm -it python:alpine sh / # python Python 3.11.1 (main, Feb 4 2023, 01:59:37) [GCC 12.2.1 20220924] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import smtplib >>> smtplib.SMTP_SSL("mail.riseup.net",465)
果不其然,卡住了。去宿主机试试看呢?
[root:~]# python Python 3.8.10 (default, Nov 14 2022, 12:59:47) [GCC 9.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import smtplib >>> smtplib.SMTP_SSL("mail.riseup.net",465) <smtplib.SMTP_SSL object at 0xffffa1148610> >>>
没问题哎。看着上面有TLS/SSL connection has been closed(EOF),难道是OpenSSL的问题,试试 python
而不是python:alpine
呢?
也不行。
是因为arm64有bug吗?但是我的电脑没问题啊🤔找了一台x86_64的试了一下也没问题。
这么排除下来,问题就是容器的网络了。默认来说docker的默认网络上bridge模式。Bridge是通过iptables去做转发的,之前在《我的ufw怎么又不好用了?使用docker时如何拒绝非cloudflare访问》中提到过。
切换到host模式试试看?
[root:~]# docker run --rm --network host -it python:alpine sh / # python Python 3.11.1 (main, Feb 4 2023, 01:59:37) [GCC 12.2.1 20220924] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import smtplib >>> smtplib.SMTP_SSL("mail.riseup.net",465) <smtplib.SMTP_SSL object at 0xffff96122ed0> >>>
果然,那为什么bridge模式不行host就可以呢?
看了一眼iptables,突然看到这么一条
Chain PREROUTING (policy ACCEPT) target prot opt source destination REDIRECT tcp -- anywhere anywhere tcp dpts:telnet:finger redir ports 16698 REDIRECT tcp -- anywhere anywhere tcp dpts:81:442 redir ports 16698 REDIRECT tcp -- anywhere anywhere tcp dpts:snpp:1000 redir ports 16698 DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
这不是之前为了方便梯子使用,把23-1000中除了80和443的端口都给转发到本地的16698了吗?😓
删掉这条规则就好了。
其他的发邮件的办法
比如说自建,mailgun,sendgrid之类的,我个人觉得sendgrid比较不错,免费用户每天可以发100封。另外一个mailersend一个月可以发12000。同样都可以用SMTP协议手搓邮件。
人人影视分享站运行状况分享
人人影视分享站大概2021年2月初开始上线,6月的时候在 zuiyu的帮助下用React重做了前端,已经跑了整整两年啦。
两年里的收获
- 总计21000条评论,有很多热心网友都会把新出的剧集网盘分享贴到评论区,非常优秀!
- 37000个用户😂虽然可能大部分用户都不活跃
- 每日大概有几千个访问
- YYeTsBot项目收获了12.4K的star和1.7k的fork,写在简历上很有趣😂
- 前端YYeTsFE 收获了182个star和49个fork
- 爱发电得到了一些热心网友的帮助,足够域名和服务器的费用了,也不枉费我N多个小时的努力
- 加了Adsense,如果可以的话希望各位能关掉广告屏蔽器。以后我的猫猫们就是广大网友们养的了!
未来一段时间想要做的事情
- 把网站继续开下去,尽量活下去
- 优化前端,提升易用性
- 提升访问量,这很刑!
- 希望能找到人和我一起维护,
这样你也是某个10K+ star的项目都维护者了 🤩,要不我这开源有什么意思嘛
欢迎给个star或者点个广告~
https://github.com/tgbot-collection/YYeTsBot