本篇文章将介绍如何使用 Docker 快速搭建一个适用于 HomeLab 和开发阶段使用的邮件网关,用来快速聚合各种软件的通知消息。当然,你也可以用它来快速验证各种软件中的邮件配置是否正确。
如果你熟悉 Docker 的话,大概十分钟,你将会拥有一套完全属于自己的邮件通知聚合服务,而这个服务,只需要 20MB 左右的内存消耗,非常轻量。
最近在整理家里的部署的软件和服务,这些服务多数都拥有“邮件通知”的能力,并会在必要的时候,使用“发送邮件”的方式通知用户一些必要的信息,比如:任务执行完毕、敏感操作、根据计划任务跑完的数据统计摘要等。
以往部署这些软件的时候,在邮件通知功能配置上,我们的选择无非是三种:注册一个真实的邮箱,使用我们自己已经在用的邮箱账号,关闭邮件通知功能。
当软件比较少的时候,不论选择哪种方案,都是可以的,因为我们的一次性操作和维护成本都比较低。
但当我们部署了越来越多的软件和服务之后,关闭邮件通知属于“鸵鸟行为”,是不推荐的;在不能100%确定软件可靠性的前提下,所有软件共享一个邮箱账号,显然是不安全的;最可靠的方案,便是为为每一个软件配置不同的邮箱账号。
而如果为每一个软件都配置独立的邮箱账号,维护邮箱账号的时间成本,将会变得不可忽视,因为你永远不知道什么时候、哪一个邮箱账号会有问题,以及在什么时候你会漏掉重要的应用消息。
所以,我开始寻找一个适用于个人或者小团队的、私有化部署的邮件网关方案,降低账号的维护成本和经济成本,以及尽可能减少不必要的公网数据交换。
为了解决上面的问题,一般可以选择两类软件方案:邮局类软件、邮件测试网关。
我们先来聊聊邮局类应用。
邮局类软件,顾名思义,和我们日常使用的 GMail、Outlook、QQ 邮箱、163 邮箱等等。在 GitHub 上,我们也可以找到不少优秀的邮局软件应用,比如下面这些:
上面的开源方案都可以作为我们日常使用的云服务、知名邮件厂商的替代方案使用。
但是通常情况下,这类软件会包含非常多的组件和能力,比如:Web 界面、多账户支持、多种邮局聚合、各种邮件协议支持、邮件推送、垃圾邮件审查、邮件防火墙、各种复杂的邮件相关的 DNS 支持等等。
随着软件功能的丰富完善,软件运行过程中的资源消耗和使用中的功能复杂度自然也就上去了,加上这几个头部的项目,技术选型多是 Ruby、Python,资源使用自然更是“雪上加霜”。
考虑到我不需要多用户支持,并且我希望我的应用始终是轻量可靠的。所以,我将目光转向了:测试网关类应用。
坦白说,能够符合我前文中提到的大部分需求,并具备比较低的资源占用的项目并不多。如果再限制能够快速进行功能验证(跑起来看效果)的项目,那就更屈指可数啦:
在简单使用之后,我选择了以第二个项目,将它作为代码基进行二次开发。毕竟基于在以往项目中的经验,相比较 Ruby 的性能和效率,我对 Node 更有信心。
如果你等不及验证效果,可以跳过下面的小节,直接阅读文章的 “使用 Docker 进行快速体验”部分。
从项目当前出现的问题和社区里的反馈里,我们可以看到几个比较明显的问题:
所以,我花了一些时间,针对原来的代码做了一些调整:
如果你好奇到底改了哪些内容的话,可以看这里的提交记录:https://github.com/maildev/maildev/compare/master…soulteary:master
接下来,我们来看看如何通过容器快速使用这个“邮件工具”吧。
如果我们想启动一个“邮件网关”,可以直接使用“一句话”的容器命令来解决战斗:
docker run -p 1080:1080 -p 1025:1025 soulteary/maildev
当命令执行完毕,我们将能够看到类似下面的日志输出:
MailDev using directory /tmp/maildev-1
MailDev webapp running at http://0.0.0.0:1080
MailDev SMTP Server running at 0.0.0.0:1025
接着在浏览器中打开 http://0.0.0.0:1080
,就能看到下图一样的收件箱界面了。
如果我们需要测试邮件聚合功能是否能够正常工作,只需要使用邮件客户端、配置任意用户名和密码,向 0.0.0.0:1025
端口发送邮件,就能够看到效果啦。
还记得上文中需要配置不同账号的问题吗?是不是很轻松的就解决啦?甚至你还可以配置邮件转发真实邮箱、限制只接收某些账号的邮件消息。
相比较使用客户端,我更喜欢使用代码来做快速验证。
这里为了方便描述,我使用 Node.js 写了一个非常简单的发信脚本:
'use strict'
const nodemailer = require('nodemailer')
async function main () {
const { user, pass } = await nodemailer.createTestAccount()
let transporter = nodemailer.createTransport({
host: '0.0.0.0',
port: 1025,
auth: { type: 'login', user, pass }
})
// send mail with defined transport object
let info = await transporter.sendMail({
from: '\'Fred Foo \' ' , // sender address
to: '[email protected], [email protected]', // list of receivers
subject: 'Hello ✔', // Subject line
text: 'Hello world?', // plain text body
html: 'Hello world?' // html body
})
console.log('Message sent: %s', info.messageId)
// Message sent:
// Preview only available when sending through an Ethereal account
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info))
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}
main().catch(console.error)
将上面的代码保存为 example-sendmail.js
,接着执行 node example-sendmail.js
,顺利的话,我们将看到类似下面的日志输出:
Message sent: <c9867b60-8c5d-df8d-2476-39f5dd77f856@example.com>
Preview URL: false `
接着,在浏览器中打开 http://0.0.0.0:1080
,我们将看到 MailDev 的界面中多了一份意料之中的“邮件”,邮件正文正是我们上面写代码中的内容。
在不进行额外的代码调整之前,我们多重复几次上面的发信操作,就可以模拟出日常学习和工作中各种应用的邮件通知发送场景。
此时,MailDev 的列表中就会实时展示新到的“邮件”了。
为了方便我的老读者们,让大家能够一起偷懒,按照惯例,我提供一个简单的容器编排配置文件:
version: '3'
services:
maildev:
image: soulteary/maildev
restart: always
environment:
- TZ=Asia/Shanghai
- MAILDEV_WEB_PORT=1080
- MAILDEV_SMTP_PORT=1025
ports:
- "1080:1080"
- "1025:1025"
将上面的内容保存为 docker-compose.yml
,接着使用 docker-compose up -d
启动应用,和上文提到的一样,我们就能够在浏览器中访问 http://localhost:1080
来浏览和管理“邮件内容”,并通过 1025
端口来进行邮件汇聚操作啦。
和之前提到过的其他的项目一样,接下来我将持续改进这个项目。短时间内,我希望它能够更好的支持 WebHook、并和一些消息推送软件进行打通,更好的支持我的 HomeLab 场景。
如果你对这个项目感兴趣、又比较“心急”的话,可以访问项目源代码:https://github.com/soulteary/maildev 进行 DIY。当然,也欢迎你在项目 issue 中留下你对这个项目的建议和想法。
–EOF
我们有一个小小的折腾群,里面聚集了几百位喜欢折腾的小伙伴。
在不发广告的情况下,我们在里面会一起聊聊软硬件、HomeLab、编程上的一些问题,也会在群里不定期的分享一些技术沙龙的资料。
喜欢折腾的小伙伴欢迎扫码添加好友。(添加好友,请备注实名,注明来源和目的,否则不会通过审核)
关于折腾群入群的那些事
本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)
本文作者: 苏洋
创建时间: 2022年03月15日
统计字数: 5362字
阅读时间: 11分钟阅读
本文链接: https://soulteary.com/2022/03/15/build-a-lightweight-mail-gateway-for-homelab-using-docker.html