Ubuntu 22.04 安装 chasquid 指南

Ubuntu 22.04.5 LTS 从零安装 chasquid 的双路线实测:apt 官方仓库(1.8-1ubuntu0.3,socket 激活)与源码编译上游 v1.19.0(Go 1.26、make install、DKIM 签名),覆盖证书/域名/用户配置、systemd 托管、25/465/587 三端口端到端收发验证与三起启动/投递故障排障实录。

chasquid邮件服务器chasquidUbuntu2026/10/21

Ubuntu 22.04 安装 chasquid 指南

目标:在 Ubuntu 22.04 LTS 服务器上从零安装并跑通 chasquid 邮件服务器,覆盖「apt 官方仓库安装(1.8-1ubuntu0.3)」与「源码编译安装上游最新版(v1.19.0)」两条完整路线,包含证书/域名/用户配置、systemd 托管、三端口(25/465/587)收发验证与全程排障实录。本指南的全部命令与回显均在 Ubuntu 22.04.5 LTS(x86_64,主机名 mail.chasquid.example)服务器上实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(jammy),x86_64
  • 主机名:mail.chasquid.example(安装前已用 hostnamectl set-hostname 设定)
  • chasquid 版本基准(双源实查,查询日期 2026-10-21):
    • Ubuntu jammy universe 仓库:1.8-1ubuntu0.3(jammy-updates / jammy-security)
    • 上游 GitHub 最新稳定版:v1.19.0(2026-10-17 发布)
  • 实测依赖软件:openssl(自签名证书)、procmail(本地投递 MDA)、python3(系统自带,模拟 SMTP 客户端验证)、Go 1.26.0(仅源码编译方案需要)
  • 关键路径:配置 /etc/chasquid/,运行数据 /var/lib/chasquid/,二进制 /usr/bin/chasquid(apt 方案)或 /usr/local/bin/chasquid(源码方案)
  • 示例域名:chasquid.example(邮件域)、mail.chasquid.example(服务器主机名/证书 CN),实验环境无真实 DNS,MX/SPF 相关外发仅验证到协议层

二、前置条件

安装前确认以下事项,逐条给出检查命令与实测回显。

2.1 确认系统与架构

cat /etc/os-release | head -2 && uname -m

实测回显:

PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
x86_64

2.2 确认 25/465/587 端口未被占用

邮件端口是冲突高发区(Postfix、Exim、sendmail 等常预装并占用 25 端口):

ss -ltn | grep -E ':(25|465|587)\b' || echo "端口空闲"

实测回显(安装前):

端口空闲

⚠️ 注意:若输出中出现占用记录(如 LISTEN 0 100 0.0.0.0:25 ... postfix),说明系统预装了其他 MTA,必须先 sudo apt purge postfix exim4-* 并确认卸载干净,否则 chasquid 起来后无法绑定端口。

2.3 安装基础工具

sudo apt-get update
sudo apt-get install -y openssl procmail iproute2

实测回显(输出节选,实测首尾):

Get:1 http://archive.ubuntu.com/ubuntu jammy InRelease [270 kB]
...
Processing triggers for libc-bin (2.35-0ubuntu3.15) ...

各工具用途:openssl 用于自签名证书(生产环境建议 Let's Encrypt);procmail 作为本地投递 MDA(默认的 maildrop 在无 courier-authdaemon 时会失败,见 8.2 节排障实录);iproute2 提供 ss 端口检查命令。

三、版本选型说明

chasquid 在 Ubuntu 22.04 上有两条可选版本线,选型前先看清差异:

基准版本来源DKIM 签名队列参数(max_queue_items 等)适用
发行版基准1.8-1ubuntu0.3Ubuntu jammy universe❌ 无(1.14 才引入)❌ 无求稳、用包管理、接受旧版
上游最新版v1.19.0(2026-10-17)GitHub Releases✅ 内建✅ 有要新特性、追上游

版本差异的量化说明(查询日期 2026-10-21):

  • jammy 仓库的 1.8 距今约落后 11 个 minor 版本;但该包仍在 jammy-updates/jammy-security 双通道获得安全维护;
  • Debian trixie(stable)当前为 1.15.0-1,介于两者之间;
  • 上游发布节奏约为每年 2~3 个 minor 版本(v1.15.0 2025-01 → v1.16.0 2025-06 → v1.17.0 2025-11 → v1.18.0 2026-06 → v1.19.0 2026-10)。

建议:生产服务器优先选方案 A(apt),版本虽旧但走安全通道、升级卸载干净;需要 DKIM 内建签名(1.14+)或队列调优参数时选方案 B(源码编译 v1.19.0)。两条路线的二进制名、配置文件路径完全一致,可互相替换。

四、方案 A:apt 官方仓库安装(1.8-1ubuntu0.3)

本方案用 Ubuntu 官方仓库直接安装 chasquid,全程约 3 分钟,获得带 systemd 集成与 man 手册的完整包。

4.1 安装软件包

sudo apt-get install -y chasquid

实测回显(关键行):

Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
  chasquid
0 upgraded, 1 newly installed, 0 to remove and 3 not upgraded.
Need to get 7045 kB of archives.
After this operation, 26.1 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 chasquid amd64 1.8-1ubuntu0.3 [7045 kB]
Selecting previously unselected package chasquid.
(Reading database ... 6535 files and directories currently installed.)
Preparing to unpack .../chasquid_1.8-1ubuntu0.3_amd64.deb ...
Unpacking chasquid (1.8-1ubuntu0.3) ...
Setting up chasquid (1.8-1ubuntu0.3) ...
Created symlink /etc/systemd/system/multi-user.target.wants/chasquid.service → /lib/systemd/system/chasquid.service.

⚠️ 注意:在裁剪过的最小化系统环境里,可能出现 policy-rc.d returned 101, not running 'start chasquid.service' 附加行——这是安装器被 /usr/sbin/policy-rc.d 策略文件拦住了服务自动启动(常见于无完整 systemd 的环境)。标准 Ubuntu 服务器不会有该现象;若遇到,安装完成后手动 sudo systemctl start chasquid.service 即可。

4.2 包内容与文件清单

确认包安装了哪些东西:

dpkg -L chasquid | grep -vE '/usr/share/(doc|man)/|copyright'

实测回显:

/.
/etc
/etc/chasquid
/etc/chasquid/README
/etc/chasquid/certs
/etc/chasquid/certs/README.certs
/etc/chasquid/chasquid.conf
/etc/chasquid/domains
/etc/chasquid/hooks
/etc/chasquid/hooks/post-data
/lib
/lib/systemd
/lib/systemd/system
/lib/systemd/system/chasquid-smtp.socket
/lib/systemd/system/chasquid-submission.socket
/lib/systemd/system/chasquid-submission_tls.socket
/lib/systemd/system/chasquid.service
/usr
/usr/bin
/usr/bin/chasquid
/usr/bin/chasquid-util
/usr/bin/mda-lmtp
/usr/bin/smtp-check
/usr/share
/usr/share/man/man1
/usr/share/man/man5
/var
/var/lib
/var/lib/chasquid

解读:

  • 二进制 4 件套:chasquid(守护进程)、chasquid-util(用户/别名/配置管理 CLI)、mda-lmtp(LMTP 投递代理)、smtp-check(外发路径诊断工具);
  • systemd 单元 4 个:服务本体 chasquid.service + 3 个 socket 单元(25/587/465 各一个),即 Ubuntu 包采用 systemd socket 激活形态,端口由 socket 单元持有;
  • 配置骨架:/etc/chasquid/(主配置、证书目录、域名目录、hooks 示例);
  • man 手册:chasquid(1)、chasquid-util(1)、mda-lmtp(1)、smtp-check(1)、chasquid.conf(5)。

查看版本:

chasquid --version

实测回显:

chasquid 1.8-1ubuntu0.3 (source date: 2024-11-15 18:13:39 +0000 UTC)

4.3 生成证书

chasquid 要求至少一张 TLS 证书才肯启动。实验环境用 openssl 自签名(生产环境把 certbot 的 /etc/letsencrypt/live/<域名>/ 软链进 certs 目录即可,结构与 chasquid 完全兼容):

sudo mkdir -p /etc/chasquid/certs/mail.chasquid.example
sudo openssl req -x509 -newkey rsa:2048 \
  -keyout /etc/chasquid/certs/mail.chasquid.example/privkey.pem \
  -out /etc/chasquid/certs/mail.chasquid.example/fullchain.pem \
  -days 3650 -nodes -subj "/CN=mail.chasquid.example"
sudo chown -R chasquid:chasquid /etc/chasquid/certs

实测回显(openssl 关键行,RSA 密钥生成进度字符已略):

-----

验证证书文件已生成且属主正确:

ls -l /etc/chasquid/certs/mail.chasquid.example/

实测回显:

-rw-r--r-- 1 chasquid chasquid 1025 Oct 21 02:13 fullchain.pem
-rw------- 1 chasquid chasquid 1704 Oct 21 02:13 privkey.pem

4.4 建域与建用户

chasquid 的域名以「目录」形式存在:/etc/chasquid/domains/<域名>/。用 chasquid-util 建第一个用户时会自动建域:

sudo chasquid-util user-add admin@chasquid.example --password=q1w2e3r4

实测回显:

Creating database
Added user

查看产生的目录与文件:

ls -la /etc/chasquid/domains/ /etc/chasquid/domains/chasquid.example/

实测回显:

/etc/chasquid/domains/:
total 12
drwxr-xr-x 3 root root 4096 Oct 21 02:06 .
drwxr-xr-x 5 root root 4096 Oct 21 02:05 ..
drwxr-xr-x 2 root root 4096 Oct 21 02:06 chasquid.example

/etc/chasquid/domains/chasquid.example/:
total 12
drwxr-xr-x 2 root root 4096 Oct 21 02:06 .
drwxr-xr-x 3 root root 4096 Oct 21 02:06 ..
-rw-rw---- 1 root root  290 Oct 21 02:06 users

再建一个本地收信用户,供后续投递验证用:

sudo chasquid-util user-add lab@chasquid.example --password=q1w2e3r4
sudo chown -R chasquid:chasquid /etc/chasquid/domains

实测回显:

Added user

4.5 配置本地投递 MDA

Ubuntu 包默认 MDA 为 maildrop,它依赖 courier-authdaemon 查询系统用户,独立服务器上常直接失败。本指南改用 procmail(已在 2.3 节安装)。编辑 /etc/chasquid/chasquid.conf,把:

#mail_delivery_agent_bin: "maildrop"

改为:

mail_delivery_agent_bin: "procmail"

同时开启监控端点(排障有用,且只监听本机回环):

monitoring_address: "127.0.0.1:1099"

确认修改生效:

grep -n '^mail_delivery_agent_bin\|^monitoring_address' /etc/chasquid/chasquid.conf

实测回显:

28:monitoring_address: "127.0.0.1:1099"
35:mail_delivery_agent_bin: "procmail"

4.6 启动服务与 systemd 托管

sudo systemctl start chasquid.service

检查服务状态:

systemctl is-active chasquid.service

实测回显:

active

查看启动日志,确认三端口就位:

journalctl -u chasquid.service --no-pager -n 8 | tail -8

实测回显:

Oct 21 02:13:29 mail.chasquid.example chasquid[1085]: _ chasquid.go:113    Loading certificates
Oct 21 02:13:29 mail.chasquid.example chasquid[1085]: _ chasquid.go:122      mail.chasquid.example
Oct 21 02:13:29 mail.chasquid.example chasquid[1085]: _ chasquid.go:140    Domain config paths:
Oct 21 02:13:29 mail.chasquid.example chasquid[1085]: _ chasquid.go:263      chasquid.example
Oct 21 02:13:29 mail.chasquid.example chasquid[1085]: _ chasquid.go:267        adding users
Oct 21 02:13:29 mail.chasquid.example chasquid[1085]: _ chasquid.go:276        adding aliases
Oct 21 02:13:29 mail.chasquid.example chasquid[1085]: _ server.go:229      Server listening on [::]:465 (submission+TLS, via systemd)
Oct 21 02:13:29 mail.chasquid.example chasquid[1085]: _ server.go:229      Server listening on [::]:25 (SMTP, via systemd)
Oct 21 02:13:29 mail.chasquid.example chasquid[1085]: _ server.go:229      Server listening on [::]:587 (submission, via systemd)

via systemd 字样即 socket 激活形态的标志:端口由 socket 单元持有,chasquid.service 重启期间 25/465/587 不掉线。设置开机自启(apt 安装时已自动 enable,此处确认):

systemctl is-enabled chasquid.service

实测回显:

enabled

确认监听:

ss -ltn | grep -E ':(25|465|587|1099)\b'

实测回显:

LISTEN 0      4096               *:587             *:*
LISTEN 0      4096               *:25              *:*
LISTEN 0      4096               *:465             *:*
LISTEN 0      4096       127.0.0.1:1099      0.0.0.0:*

五、方案 B:源码编译安装上游 v1.19.0

本方案从官方发布 tarball 编译最新版,适合需要 DKIM 内建签名(1.14+)与队列调优参数的场景。

5.1 安装 Go 工具链

chasquid v1.19.0 的 go.mod 要求 Go 1.26.0,而 jammy 仓库的 golang-go 仅 1.18,必须装官方工具链:

wget https://go.dev/dl/go1.26.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.26.0.linux-amd64.tar.gz
/usr/local/go/bin/go version

实测回显:

go version go1.26.0 linux/amd64

编译依赖再补两件:

sudo apt-get install -y make git

实测回显(输出节选):

Processing triggers for man-db (2.10.2-1) ...

5.2 下载并编译

wget https://github.com/albertito/chasquid/archive/refs/tags/v1.19.0.tar.gz -O chasquid-1.19.0.tar.gz
tar xzf chasquid-1.19.0.tar.gz
cd chasquid-1.19.0
export PATH=/usr/local/go/bin:$PATH
export GOPROXY=https://goproxy.cn,direct
make all

实测回显(make 编译各目标,模块下载行已略):

go build -ldflags="\
        -X main.version=`git describe --always --long --dirty --tags` \
        -X main.sourceDateTs=`git log -1 --format=%ct` \
        "
go build  ./cmd/chasquid-util/
go build  ./cmd/smtp-check/
go build  ./cmd/mda-lmtp/
go build  ./cmd/dovecot-auth-cli/

确认五个二进制全部产出:

ls -la chasquid chasquid-util smtp-check mda-lmtp dovecot-auth-cli

实测回显:

-rwxr-xr-x 1 root root 18230693 Oct 21 02:22 chasquid
-rwxr-xr-x 1 root root 10919930 Oct 21 02:22 chasquid-util
-rwxr-xr-x 1 root root  3411993 Oct 21 02:22 dovecot-auth-cli
-rwxr-xr-x 1 root root  3624190 Oct 21 02:22 mda-lmtp
-rwxr-xr-x 1 root root 10488622 Oct 21 02:22 smtp-check

⚠️ 注意:直接对 tarball 执行 make 时,git describe 取不到版本(tarball 不是 git 仓库),主程序版本号会显示为 00010101。带版本参数重新编译即可修复:

TS=$(date -d "2026-10-17 18:17:53 UTC" +%s)
make chasquid VERSION=v1.19.0 SOURCE_DATE_EPOCH=$TS
./chasquid -version

实测回显:

chasquid v1.19.0 (source date: 2026-10-17 18:17:53 +0000 UTC)

5.3 安装二进制与配置骨架

sudo make install-binaries VERSION=v1.19.0 SOURCE_DATE_EPOCH=$TS
sudo make install-config-skeleton

实测回显(install-binaries 关键行):

mkdir -p /usr/local/bin/
cp -a chasquid chasquid-util smtp-check mda-lmtp /usr/local/bin/

install-config-skeleton 实测回显(关键行):

'etc/chasquid' -> '/etc/chasquid'
'etc/chasquid/README' -> '/etc/chasquid/README'
'etc/chasquid/certs' -> '/etc/chasquid/certs'
'etc/chasquid/chasquid.conf' -> '/etc/chasquid/chasquid.conf'
'etc/chasquid/domains' -> '/etc/chasquid/domains'
'etc/chasquid/hooks' -> '/etc/chasquid/hooks'
'etc/chasquid/hooks/post-data' -> '/etc/chasquid/hooks/post-data'
'etc/fail2ban' -> '/etc/fail2ban'
'etc/fail2ban/filter.d/chasquid.conf' -> '/etc/fail2ban/filter.d/chasquid.conf'
'etc/systemd/system/chasquid.service' -> '/etc/systemd/system/chasquid.service'
mkdir: created directory '/var/lib/chasquid'
mode of '/var/lib/chasquid' changed from 0755 (rwxr-xr-x) to 0700 (rwx------)
changed ownership of '/var/lib/chasquid' from root:root to mail:mail

解读骨架安装了三块内容:

  1. /etc/chasquid/:配置骨架。注意其 certs 是一个指向 /etc/letsencrypt/live/ 的软链——这是给 certbot 用户准备的,没有 letsencrypt 时需要删掉软链换成真实目录;
  2. /etc/systemd/system/chasquid.service:上游形态的 systemd 单元(与 Ubuntu 包的 socket 激活不同,它直接监听端口);
  3. /etc/fail2ban/filter.d/chasquid.conf:fail2ban 过滤器(配合 fail2ban 封禁认证爆破 IP)。

查看上游单元内容:

cat /etc/systemd/system/chasquid.service

实测回显:

[Unit]
Description=chasquid mail daemon (service)

[Service]
ExecStart=/usr/local/bin/chasquid \

#       -v=3 \
#       --log_dir=/var/log/chasquid/ \
#       --alsologtostderr \

Type=simple
Restart=always

User=mail
Group=mail

# Let chasquid listen on ports < 1024.
AmbientCapabilities=CAP_NET_BIND_SERVICE

# Simple security measures just in case.
ProtectSystem=full

[Install]
WantedBy=multi-user.target

要点:进程以 mail:mail 用户运行,CAP_NET_BIND_SERVICE 允许绑定 25 等低端口,ProtectSystem=full 限制对系统目录的写权限。

5.4 配置证书、域名、用户与监听地址

先处理 certs 软链并生成证书:

sudo rm -f /etc/chasquid/certs
sudo mkdir -p /etc/chasquid/certs/mail.chasquid.example
sudo openssl req -x509 -newkey rsa:2048 \
  -keyout /etc/chasquid/certs/mail.chasquid.example/privkey.pem \
  -out /etc/chasquid/certs/mail.chasquid.example/fullchain.pem \
  -days 3650 -nodes -subj "/CN=mail.chasquid.example"
sudo chown -R mail:mail /etc/chasquid/certs /var/lib/chasquid

建域建用户(1.19 的 chasquid-util 落在 /usr/local/bin):

/usr/local/bin/chasquid-util user-add admin@chasquid.example --password=q1w2e3r4
/usr/local/bin/chasquid-util user-add lab@chasquid.example --password=q1w2e3r4
sudo chown -R mail:mail /etc/chasquid/domains

实测回显:

Creating database
Added user
Added user

上游骨架的 chasquid.conf 默认已启用直连监听(与自带单元配套),确认三个监听参数与监控地址:

grep -n '^smtp_address\|^submission_address\|^submission_over_tls_address' /etc/chasquid/chasquid.conf

实测回显:

17:smtp_address: ":25"
23:submission_address: ":587"
29:submission_over_tls_address: ":465"

把默认关闭的监控端点打开(追加或去掉注释):

sudo sed -i 's|^#monitoring_address: "127.0.0.1:1099"|monitoring_address: "127.0.0.1:1099"|' /etc/chasquid/chasquid.conf
grep -n '^monitoring_address' /etc/chasquid/chasquid.conf

实测回显:

34:monitoring_address: "127.0.0.1:1099"

5.5 启动服务并验证

sudo systemctl daemon-reload
sudo systemctl enable --now chasquid.service

实测回显:

Created symlink /etc/systemd/system/multi-user.target.wants/chasquid.service → /etc/systemd/system/chasquid.service.
systemctl is-active chasquid.service
journalctl -u chasquid.service --no-pager -n 10 | tail -10

实测回显:

active
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ chasquid.go:91     Loading certificates:
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ chasquid.go:264      mail.chasquid.example
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ monitoring.go:92   Monitoring HTTP server listening on 127.0.0.1:1099
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ chasquid.go:104    Loading domains:
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ chasquid.go:338      chasquid.example (2 users, 0 aliases, 0 DKIM keys)
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ server.go:352      Incoming connection limit: 262143
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ server.go:364      Server listening on :25 (SMTP)
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ server.go:364      Server listening on :587 (submission)
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ server.go:364      Server listening on :465 (submission+TLS)
Oct 21 02:23:46 mail.chasquid.example chasquid[8389]: _ localrpc.go:68     LocalRPC.Server /var/lib/chasquid/localrpc-v1: Listening

对比方案 A 的日志可见 1.19 的增强输出:Max queue items: 200、Give up send after: 20h0m0s(新队列参数)、DKIM 密钥计数、LocalRPC 管理套接字(供 chasquid-util aliases-resolve 等运行时查询)。确认监听:

ss -ltn | grep -E ':(25|465|587|1099)\b'

实测回显:

LISTEN 0      4096       127.0.0.1:1099      0.0.0.0:*
LISTEN 0      4096               *:587             *:*
LISTEN 0      4096               *:25              *:*
LISTEN 0      4096               *:465             *:*

⚠️ 注意:方案 B 的服务以 mail 用户运行,配置目录属主需保持 mail:mail;与方案 A 的 chasquid 用户不同,混用两种方案时注意 chown 对应用户。

六、方案对比与选择建议

维度方案 A(apt)方案 B(源码编译)
版本1.8-1ubuntu0.3(jammy-updates 维护)v1.19.0(上游最新)
二进制位置/usr/bin//usr/local/bin/
端口形态systemd socket 激活(3 个 socket 单元)进程直接监听(CAP_NET_BIND_SERVICE)
运行用户chasquidmail
DKIM 内建签名❌(1.14 才有)✅
队列参数(max_queue_items / give_up_send_after)❌✅
监控端点✅✅
升级/卸载apt 一条命令手动替换二进制
需要联网是(仓库)是(go.dev + GitHub + Go 模块代理)

选择建议:能接受 1.8 的功能面就选方案 A,把升级交给 apt 安全通道;需要 DKIM 签名(自建域发信的送达率刚需)、MTA-STS 或队列参数,选方案 B。两方案配置文件同构,未来可无痛迁移(先 purge 方案 A 再装方案 B 时记得处理 /etc/chasquid/domains、/etc/chasquid/certs 残留属主)。

七、安装后验证:端到端收发实测

本节用系统自带的 python3 模拟 SMTP 客户端,对三个端口逐一验证。以下为验证脚本 send_test.py 的实测记录(服务器本机执行)。

7.1 25 端口:EHLO 能力与明文提交

python3 - <<'EOF'
import smtplib
s = smtplib.SMTP("127.0.0.1", 25)
code, banner = s.ehlo("client.chasquid.example")
print(code, banner.decode())
print("--- features ---")
for k in sorted(s.esmtp_features):
    print(k)
s.quit()
EOF

实测回显:

250 mail.chasquid.example - Your hour of destiny has come.
--- features ---
8bitmime
enhancedstatuscodes
help
pipelining
size
smtputf8
starttls

EHLO 应答可见 SIZE 上限 52428800(即 max_data_size_mb 默认 50MB)、SMTPUTF8 国际化与 STARTTLS 支持。banner 是 chasquid 的彩蛋句。

7.2 本地投递闭环

发起一封本地投递(发件 root@chasquid.example → 收件 lab@chasquid.example,lab 为系统用户,procmail 投入 /var/mail/lab):

python3 - <<'EOF'
import smtplib
from email.message import EmailMessage
msg = EmailMessage()
msg["From"] = "root@chasquid.example"
msg["To"] = "lab@chasquid.example"
msg["Subject"] = "chasquid 1.8 first mail"
msg.set_content("hello")
s = smtplib.SMTP("127.0.0.1", 25)
s.ehlo("client.chasquid.example")
s.send_message(msg)
print("send_message OK")
s.quit()
EOF

实测回显:

send_message OK

验证信件落地:

ls -l /var/mail/lab && tail -20 /var/mail/lab

实测回显(信件头部关键行):

-rw-rw---- 1 lab mail 586 Oct 21 02:20 lab
From root@chasquid.example  Wed Oct 21 02:20:10 2026
>From chasquid  Wed Oct 21 02:20:10 2026
Received-SPF: none (lookup chasquid.example on 192.168.146.2:53: no such host)
Received: from [127.0.0.1] (client.chasquid.example)
        by mail.chasquid.example (chasquid) with ESMTP
        (over SMTP, plain text!, envelope from "root@chasquid.example")
        ; Wed, 21 Oct 2026 02:20:10 +0000
From: root@chasquid.example
To: lab@chasquid.example
Subject: chasquid 1.8 first mail
...

Received 头里的 over SMTP, plain text! 是 chasquid 对明文会话的显式标注——它同时把这次会话记入 domaininfo 的 TLS 能力追踪。

7.3 587 端口:STARTTLS + 认证提交

python3 - <<'EOF'
import smtplib
from email.message import EmailMessage
msg = EmailMessage()
msg["From"] = "lab@chasquid.example"
msg["To"] = "lab@chasquid.example"
msg["Subject"] = "auth submission test"
msg.set_content("via 587 with auth")
s = smtplib.SMTP("127.0.0.1", 587)
s.ehlo("client.chasquid.example")
s.starttls()
s.login("lab@chasquid.example", "q1w2e3r4")
print("AUTH OK, features after tls:", sorted(s.esmtp_features))
s.send_message(msg)
print("send_message OK")
s.quit()
EOF

实测回显:

AUTH OK, features after tls: ['8bitmime', 'auth', 'enhancedstatuscodes', 'help', 'pipelining', 'size', 'smtputf8']
send_message OK

注意 auth 能力只在 STARTTLS 之后才出现——chasquid 禁止明文认证,这是它的默认安全基线。

7.4 465 端口:隐式 TLS + 后缀投递

python3 - <<'EOF'
import smtplib
from email.message import EmailMessage
msg = EmailMessage()
msg["From"] = "admin@chasquid.example"
msg["To"] = "lab+news@chasquid.example"
msg["Subject"] = "implicit tls 465 + suffix test"
msg.set_content("via 465 SMTP_SSL")
s = smtplib.SMTP_SSL("127.0.0.1", 465)
s.ehlo("client.chasquid.example")
s.login("admin@chasquid.example", "q1w2e3r4")
s.send_message(msg)
print("465 SMTP_SSL + AUTH OK, sent to lab+news@")
s.quit()
EOF

实测回显:

465 SMTP_SSL + AUTH OK, sent to lab+news@
tail -3 /var/mail/lab

实测回显:

via 465 SMTP_SSL

收件人写的 lab+news@,信件照样投进了 lab 的邮箱——后缀分离(suffix_separators 默认 +)按预期工作。

7.5 方案 B 补充验证:DKIM 签名

v1.19.0 内建 DKIM,生成密钥并重启后,认证用户发出的信会自动签名:

sudo /usr/local/bin/chasquid-util dkim-keygen chasquid.example
sudo chown mail:mail /etc/chasquid/domains/chasquid.example/dkim:*.pem
sudo systemctl restart chasquid.service

实测回显(dkim-keygen,密钥体已节选):

Key written to "/etc/chasquid/domains/chasquid.example/dkim:20261021.pem"

20261021._domainkey.chasquid.example    TXT     "v=DKIM1; k=rsa; p=MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAu1cVzyS7S0cnhPtkwH6FBaGs/UsOqqRVcYSKEZNvWGwTH+D/pI6NL1eNH7412EAqbMtaIqe6ejlS0BmrpmJxZmR+AXDQbgPUw76X9lrYklOKeHSBfzDxxKlAdzXd/gMwmapFbA+vnEQS+i/ilKzBp8kJE+3vtL+CRJxcEbGfUzUbHuarIAKEDWoav3fSshlX7RFhOvXxO7XaYJrrO7a5+CEI8wJclbhNsiVJ83gVlYcTkKWvVb1O53w9sm1FjPOMnw+ZI4dmbsHcFstmqeOHCXdokFfqAmP/GCUkkgOWfDRxSGbrsmglbef/bZbKILM56d+gw9crFHbVtDI7qjFLGCLr93iPDY3yiM6Gq0aEoO4LppXSxDKT+Q+Usx+lQ0HQeNdPr7vO8r40mpZcuo5d6iR/24/0Ya/5NQ3KvlNuoc0b3Tb/ahyW+KvQVCqGgoLKs82SxFygIyqtGEIcje/gBr5vW2FU3A+FJH1HlkslseQ36fyo8K058KGjIjv85AEDAgMBAAE="

用 7.3 的认证提交方式再发一封,检查落地信件头部:

awk '/^From admin@chasquid.example/,0' /var/mail/lab | grep -E '^DKIM-Signature|^Subject' | head -4

实测回显:

From admin@chasquid.example  Wed Oct 21 02:25:40 2026
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
Subject: chasquid 1.19 dkim+delivery test

DKIM-Signature 头已自动附加(rsa-sha256,relaxed/relaxed),把上一条输出中的 TXT 记录发布到 DNS 后即可完成 DKIM 全链路。

八、常见问题(FAQ)

8.1 启动失败:No entries found in "domains/"

现象:systemctl start 后服务很快退出,systemctl is-active 显示 failed。

journalctl -u chasquid.service --no-pager | tail -6

实测回显:

Oct 21 02:06:11 mail.chasquid.example chasquid[468]: _ chasquid.go:113    Loading certificates
Oct 21 02:06:11 mail.chasquid.example chasquid[468]: _ chasquid.go:140    Domain config paths:
Oct 21 02:06:11 mail.chasquid.example chasquid[468]: ☠ chasquid.go:300    No entries found in "domains/"
Oct 21 02:06:11 mail.chasquid.example systemd[1]: chasquid.service: Main process exited, code=exited, status=1/FAILURE

原因与解决:/etc/chasquid/domains/ 下没有任何域名目录(全新安装的初始状态即如此)。按 4.4 节执行 chasquid-util user-add <用户@域名> 建立第一个域后重启即可。同理,certs/ 为空时服务同样拒绝启动(日志会提示证书加载失败),先按 4.3 节放好证书。

8.2 投递失败:MDA delivery failed: exit status 75(maildrop 依赖问题)

现象:25 端口收信正常(信进了队列),但本地投递失败,日志出现:

journalctl -u chasquid.service --no-pager | grep -E 'MDA|failed' | tail -3

实测回显:

Oct 21 02:14:13 mail.chasquid.example chasquid[1085]: _ mda.go:80          Courier.MDA lab@chasquid.example: error: MDA delivery failed: exit status 75 - "ERR: authdaemon: s_connect() failed: No such file or directory\nmaildrop: Cannot set my user or group id.\n"
Oct 21 02:14:13 mail.chasquid.example chasquid[1085]: _ queue.go:357       Queue.SendLoop az_TncfNqfo: lab@chasquid.example temporary error: MDA delivery failed: exit status 75 - "ERR: authdaemon: s_connect() failed: No such file or directory\nmaildrop: Cannot set my user or group id.\n"
Oct 21 02:14:13 mail.chasquid.example chasquid[1085]: az_TncfNqfo from=root@chasquid.example to=lab@chasquid.example failed (temporary): MDA delivery failed: exit status 75 - "ERR: authdaemon: s_connect() failed: No such file or directory\nmaildrop: Cannot set my user or group id.\n"

原因:Ubuntu 包默认 MDA 是 maildrop,其 Debian 构建依赖 courier-authdaemon 做用户映射;没有该服务的机器上 maildrop 无法 setuid 到收件用户。解决:换 procmail(sudo apt install procmail,配置 mail_delivery_agent_bin: "procmail",见 4.5 节)。改动后队列里未投出的信会按间隔自动重试投递,无需手工干预;观察队列状态可访问监控端点 http://127.0.0.1:1099/debug/queue。

8.3 MDA 配置无效时:executable file not found(1.19 系列)

现象:改了 mail_delivery_agent_bin 却仍报错,日志形如:

Oct 21 02:25:07 mail.chasquid.example chasquid[8511]: _ mda.go:90          Courier.MDA lab@chasquid.example: error: local delivery failed: exec: "maildrop": executable file not found in $PATH (output: "")
Oct 21 02:25:07 mail.chasquid.example chasquid[8511]: _ queue.go:371       Queue.SendLoop A2uor4i9Xmc: error: lab@chasquid.example permanent error: local delivery failed: exec: "maildrop": executable file not found in $PATH (output: "")
Oct 21 02:25:07 mail.chasquid.example chasquid[8511]: _ queue.go:499       Queue.SendLoop A2uor4i9Xmc: queued DSN: vr5_CQ13n8E

原因与解决:上游骨架配置里 mail_delivery_agent_bin 默认是注释状态,直接 sed 替换注释行不会生效,实际 MDA 仍是默认值 maildrop(本机未装则报 executable not found)。正确改法是「取消注释并改值」两步合一:

sudo sed -i 's|^#mail_delivery_agent_bin: "maildrop"|mail_delivery_agent_bin: "procmail"|' /etc/chasquid/chasquid.conf
chasquid-util print-config | grep mail_delivery_agent_bin

另注意这轮日志里的两个知识点:本地投递失败属永久错误时,chasquid 会自动生成一封 DSN(退信通知,日志中的 queued DSN: vr5_CQ13n8E)回投给发件人;chasquid-util print-config 是核对生效配置的最快手段。

8.4 端口被占用:Address already in use

现象:日志报 bind: address already in use 后退出。用 2.2 节命令定位占用进程,sudo apt purge postfix 等移除竞争 MTA 后重启。socket 激活形态下还要确认 socket 单元状态:

systemctl status chasquid-smtp.socket --no-pager | head -4

实测回显(健康状态示例):

● chasquid-smtp.socket - chasquid mail daemon (SMTP sockets)
     Loaded: loaded (/lib/systemd/system/chasquid-smtp.socket; enabled; vendor preset: enabled)
     Active: active (listening)

8.5 升级到上游新版(方案 A → 方案 B 的迁移)

  1. 备份数据:sudo cp -a /etc/chasquid /root/chasquid-backup && sudo cp -a /var/lib/chasquid /root/chasquid-data-backup;
  2. sudo apt purge chasquid(用户库/证书目录若非空会被保留,属主为 chasquid);
  3. 按第五节安装 v1.19.0,运行用户变为 mail:sudo chown -R mail:mail /etc/chasquid/domains /etc/chasquid/certs /var/lib/chasquid;
  4. chasquid-util print-config 核对生效配置,1.19 会为缺失的队列参数自动落默认值(max_queue_items: 200、give_up_send_after: "20h")。

九、卸载与清理

9.1 方案 A(apt)

sudo systemctl stop chasquid.service
sudo apt purge -y chasquid

实测回显(关键行):

Purging configuration files for chasquid (1.8-1ubuntu0.3) ...
dpkg: warning: while removing chasquid, directory '/etc/chasquid/domains' not empty so not removed
dpkg: warning: while removing chasquid, directory '/etc/chasquid/certs' not empty so not removed

如提示所述,自己创建的域名/证书目录会被保留,确认不再需要时手动删除:

sudo rm -rf /etc/chasquid /var/lib/chasquid

9.2 方案 B(源码)

sudo systemctl stop chasquid.service
sudo systemctl disable chasquid.service
sudo rm -f /usr/local/bin/chasquid /usr/local/bin/chasquid-util /usr/local/bin/smtp-check /usr/local/bin/mda-lmtp
sudo rm -rf /etc/chasquid /etc/systemd/system/chasquid.service /etc/fail2ban/filter.d/chasquid.conf /var/lib/chasquid
sudo systemctl daemon-reload

如需连编译环境一起清理:

sudo rm -rf /usr/local/go /root/chasquid-1.19.0 /root/chasquid-1.19.0.tar.gz /root/go1.26.0.linux-amd64.tar.gz

十、参考链接