Email
2026-07-27
MJML(Mailjet Markup Language)是一种专门用于编写响应式 HTML 邮件的标记语言。相当于是 HTML 在电子邮件场景下的更高层的封装,由编译器生成兼容各种邮箱客户端的 HTML。主要解决邮件 HTML 的痛点:
- Gmail / Outlook / Apple Mail 支持差异巨大
- 邮件需要大量 table 布局
- CSS inline 化复杂
- 移动端适配困难
注意:MJML 只负责 UI 不含模板功能。如果需要使用变量或者其他模板语法,可以另外选择任何一种语言进行渲染,比如 Node Handlebars,Golang 模板,Python Jinja2 等。
MJML 最初由法国邮件服务公司 Mailjet 在 2015 年开源。目前项目已经独立维护,属于开源生态:
- 语法:MJML
- 编译器:Node.js 实现
- 输出:标准 HTML Email
GitHub Repository: mjmlio/mjmlio
MJML 文件格式
扩展名:.mjml
<mjml>
<mj-head>
<mj-title>Welcome</mj-title>
</mj-head>
<mj-body>
<mj-section>
<mj-column>
<mj-text font-size="20px">
Hello Woody
</mj-text>
<mj-button href="https://example.com">
Click
</mj-button>
</mj-column>
</mj-section>
</mj-body>
</mjml>
通过一下方法可以直接预览效果:
- VSCode 拓展 [MJML Official]
- 官方 MJML Live Editor
- 自己实现 Preview 服务,AI 很容易生成一个
渲染 HTML
安装:
npm install -g mjml
转换:
mjml template.mjml -o template.html
生成的 HTML 会包含:
- table 布局
- inline style
- Outlook VML兼容代码
- media query
开发者工具 Email
2026-04-05
用 perl 开发的命令行工具 swaks 用来发送邮件挺方便的,但是有些环境不便安装,我问 AI,结果推荐了 curl 命令。
-> % curl --help smtp
smtp: SMTP protocol
--crlf Convert LF to CRLF in upload
-F, --form <name=content> Specify multipart MIME data
--form-string <name=string> Specify multipart MIME data
-H, --header <header/@file> Pass custom header(s) to server
--login-options <options> Server login options
--mail-auth <address> Originator address of the original email
--mail-from <address> Mail from this address
--mail-rcpt <address> Mail to this address
--mail-rcpt-allowfails Allow RCPT TO command to fail
--oauth2-bearer <token> OAuth 2 Bearer Token
-X, --request <method> Specify request method to use
--ssl Try enabling TLS
--ssl-reqd Require SSL/TLS
我用 curl 发送了几封邮件,还真的挺好的,满足我的要求。
-
生成邮件内容:
export FROM=noreply@example.com
export RCPT=ninedoors@126.com
export USER=shanda
export PASS=6404290f99f75bf182673bcbd012c121
# AI 生成验证码邮件模板
cat > /tmp/mail.html <<EOF
From: $FROM
To: $RCPT
Subject: Your Verification Code: CODE
Content-Type: text/html; charset=UTF-8
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, initial-scale=1.0"><title>Verification Code</title><style>@media only screen and(max-width:600px){.container{width:100%!important}.mobile-padding{padding:10px!important}}</style></head><body style="margin: 0; padding: 10px; background-color: #f4f4f4; font-family: Arial, sans-serif;"><table role="presentation"align="center"border="0"cellpadding="0"cellspacing="0"width="100%"style="max-width: 600px; width: 100%; margin: 0 auto; background-color: #ffffff;"><tr><td class="mobile-padding"style="padding: 40px 20px;"><table role="presentation"width="100%"border="0"cellpadding="0"cellspacing="0"><tr><td style="padding-bottom: 30px;"><h1 style="color: #333333; margin: 0;">Verification Code</h1></td></tr></table><table role="presentation"width="100%"border="0"cellpadding="0"cellspacing="0"><tr><td style="padding: 20px 0;"><p style="color: #666666; line-height: 1.6; font-size: 16px;">Your verification code is:<h2 style="letter-spacing: 2px;">CODE</h2></p></td></tr></table></td></tr></table></body></html>
EOF
# 替换验证码内容,我不想每次发送相同内容
# sed "s/CODE/$(printf "%06d" $((RANDOM % 1000000)))/g" /tmp/mail.html > /tmp/mail2.html
sed s/CODE/$(python -c "import secrets; print('%06d' % secrets.randbelow(10**6))")/g /tmp/mail.html > /tmp/mail2.html
-
邮件发送:
curl smtp://smtp.engagelab.cc:2525 --mail-from nobody@whatever.com --mail-rcpt $RCPT --user "$USER:$PASS" --upload-file /tmp/mail2.html -vv -s 2>&1 | grep -Fv '] * '
遇到一个奇怪的现象:zsh 中 RANDOM 这样使用结果不会变更,没有时间研究,暂时忽略。
-> % echo $(printf "%06d" $((RANDOM % 1000000)))
018840
-> % echo $(printf "%06d" $((RANDOM % 1000000)))
018840
-> % echo $(printf "%06d" $((RANDOM % 1000000)))
018840
如果直接使用却会,不知道为什么:
for i in {1..5}; do echo $RANDOM done
Email
2026-01-15
- L1: Email Infrastructure (基础设施)
- L2:Email Deliverability & Trust (送达与信誉)
- Spam filtering
- Abuse mitigation
- Authentication protocols
- Reputation system
- Deliverability analytics
- ISP feedback loops
- Email hygiene / list quality
- L3:Email Marketing & Growth(营销与增长)
- Email marketing automation
- List building
- Segmentation
- Campaign orchestration
- A/B testing
- Email design & template system
- L4:Compliance & Governance(合规治理)
- GDPR / CAN-SPAM / CASL 法规框架
- Opt-in / opt-out system 订阅机制
- Data retention policies 数据保留策略
- Consent management 同意管理
- L5:Market & Ecosystem(外部生态)
- International email strategies
- Industry relations(ISP / regulators)
- Domain reputation ecosystem
Email
2026-01-14
Email
2025-08-17
谷歌(Gmail)和苹果(Apple iCloud)
Gmail: Primary(主要) Social(社交) Updates(动态) “Forums(论坛) Promotions(推广)
Apple: Primary(主要) Transactions(交易) Updates(更新) Promotions(推广)
Gmail 和 Apple 分类比较类似:
- 主要:个人邮件
- 更新/动态:资讯、订阅
- 推广:营销邮件
不同的是,谷歌搞了一个社交与论坛,因为他们有这方面的业务。
苹果则是单独列了一个交易,将订单、物流等邮件单独管理。
微软(Outlook)
这个归类方式就比较简单,可能和微软的在线业务不够丰富、市场占有率不够高(和谷歌、苹果相比)有关。
总结
这个分类就收益于 AI 的出现,体现了 ISP 对电子邮件内容的控制程度的升高。
Golang Email DNS
2025-07-08
背景知识:什么是 SPF?
SPF(Sender Policy Framework,发送方策略框架)是一种电子邮件验证协议,定义在 https://datatracker.ietf.org/doc/html/rfc7208 中。它的核心作用是让域名所有者声明:哪些 IP 地址或服务器被允许代表该域名发送邮件。
接收方邮件服务器收到邮件后,会查询发件人域名的 SPF 记录(一条 DNS TXT 记录),检查连接 IP 是否在授权列表中。这能有效防止邮件伪造和钓鱼攻击。
一条典型的 SPF 记录长这样:
v=spf1 ip4:192.0.2.0/24 include:_spf.google.com ~all
Golang 解析
注意:这个库只有 12 次提交,已经 2 年多没有更新,肯定不完备,但是放在小工具中简单使用也没有什么问题。
UPDATE: 这个库太简陋了,不如自己写一个。
mileusna/spf 是一个轻量级的 Go 语言 SPF 检查库,提供了两个核心接口:
| 功能 |
函数 |
说明 |
| SPF 校验 |
spf.CheckHost() |
给定 IP、域名和发件人,返回完整的 SPF 判定结果 |
| 记录查询 |
spf.LookupSPF() |
仅从 DNS 拉取原始 SPF TXT 字符串 |
package main
import (
"net"
"github.com/mileusna/spf"
)
func main() {
// optional, set DNS server which will be used by resolver.
// Default is Google's 8.8.8.8:53
spf.DNSServer = "1.1.1.1:53"
ip := net.ParseIP("123.123.123.123")
r := spf.CheckHost(ip, "qq.com", "service@qq.com", "");
// returns spf check result
// "PASS" / "FAIL" / "SOFTFAIL" / "NEUTRAL" / "NONE" / "TEMPERROR" / "PERMERROR"
// if you only need to retrive SPF record as string from DNS
spfRecord, _ := spf.LookupSPF("qq.com")
fmt.Println(spfRecord)
// v=spf1 include:spf.mail.qq.com -all
}
spf.CheckHost() 返回以下 7 种字符串结果之一:
| 返回值 |
含义 |
邮件处理建议 |
"PASS" |
IP 被明确授权 |
正常接收 |
"FAIL" |
IP 不在授权列表中(-all 或 -ip4 匹配失败) |
建议拒收 |
"SOFTFAIL" |
软失败(~all),IP 可能未授权但无法确定 |
接受但标记/放入垃圾箱 |
"NEUTRAL" |
策略判定为中立(?all) |
按常规流程处理 |
"NONE" |
域名无 SPF 记录或记录无法解析 |
建议拒收 |
"TEMPERROR" |
DNS 临时错误(超时、SERVFAIL 等) |
可能是 DNS 抖动,稍后重试,暂不拒收 |
"PERMERROR" |
SPF 记录存在永久错误(语法错误、多重记录等) |
配置异常,建议拒收 |
Email
2024-03-03
说明:SMTP AUTH (PLAIN / LOGIN) 属于邮件客户端身份认证机制,与上面说的邮件域名认证机制(也叫做邮件认证机制,Email Authentication)是两码事。
邮件域名认证机制包括 SPF、DKIM、DMARC 三种:
-
SPF 校验(RFC 7208):当前 SMTP 会话的客户端 IP 是否被 MAIL FROM 域名授权发送邮件。
PS:优先使用 MAIL FROM(Envelope-From)域名,若 MAIL FROM 为空(<>),则使用 HELO/EHLO 域名。
-
DKIM 校验:DKIM 通过 DKIM-Signature 头中的 d=(Signing Domain,署域)和 s=(Selector)从 DNS 获取公钥,对指定的 header 和 body 进行签名校验。
dig txt selector._domainkey.signing-domain
-
DMARC 校验(RFC 7489 Domain-based Message Authentication, Reporting, and Conformance (DMARC)):
DMARC 在 SPF、DKIM 基础上引入了域名 “对齐” (Alignment) 概念,要求邮件 FROM 头域名必须与 SPF 校验所使用的域名 或 DKIM 署域 中的至少一个保持对齐(一致),实践中通常是两者同时保持对齐。
PS:严格对齐就是要求域名部分完全一致,宽松对齐就是仅要求主域名 (eTLD + 1) 一致,对应 DMARC 记录的 aspf/adkim TAG 的值 r(relaxed mode)与 s(strict mode),如果没有指定,默认就是宽松对齐,实际上主流 MP 都没有指定。
此外,DMARC 还提供了如果校验失败的处理策略框架 (none 监控 / quarantine 隔离 / reject 拒绝) 与反馈机制 (rua 汇总报告 / ruf 失败报告)。
Email
2024-02-18
Email
2023-12-25
- 退订
- FBL 举报
- 运营商反馈
- 收件人反馈(投诉)
- 地址不存在
- 邮箱容量已满
- 平台或客户手动指定的域名或地址
- 第三方提供的黑名单地址
有些是永久禁止,有些是临时禁止(比如一个月、三个月、半年)。
Email
2023-12-05

关于 SpamHaus
Wikipedia:The SpamHaus Project
Spamhaus Project 是一个位于安道尔公国(法国和西班牙中间,498 平方公里)的国际组织,由 Steve Linford 于 1998 年创立,旨在跟踪垃圾邮件发送者和垃圾邮件相关活动。
SpamHaus 这个名字是一个伪德语表达,由林福德创造,指的是向垃圾邮件发送者发送垃圾邮件或故意向垃圾邮件发送者提供服务的互联网服务提供商或其他公司。
该组织维护了几个反垃圾邮件列表,被很多邮件服务采用。
这个列表通过基于 DNS 的黑名单(DNSBL)和白名单(DNSWL)提供,对个人和中小企业免费,大量查询使用应该是有付费服务(采用 rsync 订阅)。
SpamHaus 提供了文档《Understanding DNSBL Filtering》讲解其 DNSBL 的工作原理。
主要列表

- SBL:Spamhaus Block List,发送垃圾邮件 IP
- BCL:Spamhaus Botnet Controller List,僵尸网络
- CSS:Combined Spam Sources,属于 SBL
- DROP:Don't Route Or Peer,直接丢弃所有流量 IP,提供给防火墙使用,属于 SBL
- XBL:Exploits Block List,被劫持机器 IP
- PBL:Policy Block List,未通过身份验证滥发邮件 IP,可以自助移除
- ZEN:SBL + XBL + PBL
- DBL:Domain Block List,域名级别拉黑