DragonFly MTA v0.14 常用 CLI 命令详解

DragonFly MTA v0.14 常用 CLI 命令详解:dma 与 sendmail/mailq/newaliases 三个马甲的注入、-t/-i/-f、mailq 查队、-q 冲刷、-bq/-D 调试、退出码,以及「队列清不掉」锁排查三步定位法全回显实录。

DragonFly MTA邮件服务器自托管2026/10/25

DragonFly MTA v0.14 常用 CLI 命令详解

本文为命令篇。dma 没有 daemon 就没有 service 命令,全部运维动作落在四个可执行名字上:dma 本体与它的三个马甲 sendmail/mailq/newaliases。本文逐条给出实测命令与逐行回显(实验机 Ubuntu 22.04,deb 0.13-1build1 与源码 v0.14 并存验证),实测日期 2026-10-25。

一、命令地图

命令实际身份用途
sendmail-> dma 的符号链接注入邮件(兼容接口,绝大多数场景只用它)
mailq-> dma 的符号链接查看队列(等价 dma -bp)
newaliases-> dma 的符号链接重建别名(实际是重读校验,dma 现读现投)
dma本体注入 + 队列操作 + 调试全功能
dma-mbox-createsetuid 助手本地投递时以收件人身份开箱,不经人工调用

链接关系实测(安装篇已验证,此处回顾):

$ ls -la /usr/bin/mailq /usr/bin/newaliases /usr/sbin/sendmail
lrwxrwxrwx 1 root root 11 Nov 23  2021 /usr/bin/mailq -> ../sbin/dma
lrwxrwxrwx 1 root root 11 Nov 23  2021 /usr/bin/newaliases -> ../sbin/dma
lrwxrwxrwx 1 root root  3 Nov 23  2021 /usr/sbin/sendmail -> dma

二、注入邮件:sendmail 的两种姿势

2.1 姿势一:收件人放命令行(推荐)

printf 'From: root@mail.example.net\nTo: ops@example.com\nSubject: relay-test\n\nbody\n' | sendmail ops@example.com

命令行上的收件人就是信封收件人,报文头域里的 To: 只是展示。信封发件人默认取 发起用户@MAILNAME 域(实测中继侧收到 MAIL FROM: root@mail.example.net)。

2.2 姿势二:-t 从头域解析收件人

printf 'From: root@mail.example.net\nTo: ops@example.com\nCc: cc@example.com\nBcc: bcc@example.com\nSubject: t-flag-test\n\nbody\n' | dma -t

手册语义:-t 让 dma 解析报文的 To:、Cc:、Bcc: 三个头作为收件人,且无论是否加 -t,Bcc: 头都会从报文中删除——这是隐私保护的关键行为。适合收件人列表由上游程序动态生成的场景。

2.3 与文件/管道配合:-i 忽略孤立点

dma -i ops@example.com < 报文文件

手册语义:SMTP 协议里单独一个 . 表示报文结束,从文件读取报文时若正文里恰有孤立的点行,会被截断;-i(-oi 等价)忽略之。管道注入时同理。

三、查队列:mailq / dma -bp

队列有货时(实测,向不可达中继发信后):

# mailq
ID	: 4a496d.58a74b63d200
From	: root@mail.example.net
To	: ops@example.com

队列清空时:

# mailq
Mail queue is empty

ID 就是 spool 目录里 Q/M 文件对的后缀(Q4a496d.58a74b63d200、M4a496d.58a74b63d200),两套输出可互相印证。

四、冲刷队列:dma -q

-q 处理队列中所有滞留邮件(可选参数被忽略,为 sendmail 兼容而留)。实测它会把正在处理的条目打印出来:

# dma -q
ID	: 4a496d.58a74b63d200
From	: root@mail.example.net
To	: ops@example.com

成功后队列归零(Mail queue is empty),中继侧收到信。发行版包默认带每 5 分钟的 cron:

# cat /etc/cron.d/dma
# Flush the dma mail transfer agent's queue every five minutes.
#
*/5 *	* * *	root	[ -x /usr/sbin/dma ] && /usr/sbin/dma -q

一个实测过的坑:-q 不能与发信混在一条命令里——

# dma -q -f root@mail.example.net ops@example.com
dma: sending mail and queue operations are mutually exclusive

-q 与注入互斥,必须分开执行。

五、只入队不投递:dma -bq 与 DEFER

  • dma -bq 收件人:本次注入只落队列、不做任何投递尝试(命令级);
  • 配置 DEFER:所有注入都只入队(主机级),统一靠 dma -q 冲刷。

两者配合 cron 定时冲刷,就是手册推荐给「非永久在线机器」的攒批模式。-b 的其余 mode(除 -bp/-bq)被忽略,同样是 sendmail 兼容设计。

六、发件人控制:-f / -r / EMAIL

三个来源按优先级:MASQUERADE > -f(-r 等价)> EMAIL > 默认。EMAIL 环境变量实测(配置篇四级优先链的第三级):

EMAIL=alerts@example.net sh -c "printf 'Subject: email-env-test\n\nvia EMAIL env\n' | dma ops@example.com"

中继侧对拍结果:

[01:17:16] MAIL FROM: alerts@example.net

而同机 root 的默认注入是 MAIL FROM: root@mail.example.net——EMAIL 生效无疑。-f 与 MASQUERADE 的覆盖关系同手册,验收方法一致:注入后在中继侧看 MAIL FROM 实际值。

七、调试:-D 前台运行与 syslog 定位

-D 让 dma 不转入后台、错误直接打到当前终端,配合 -q 就是队列冲刷的前台模式:

# dma -Dq
(正常时静默,exit 0;对端报错时会直接回显 SMTP 错误)

更完整的轨迹在 syslog(装了 rsyslog 的主机上是 /var/log/mail.log)。实测一封「STARTTLS + AUTH LOGIN 外发成功」信的完整链路原文:

Oct 25 01:17:00 mail01 dma[4a6c2b]: new mail from user=root uid=8 envelope_from=<root@mail.example.net>
Oct 25 01:17:00 mail01 dma[4a6c2b]: mail to=<ops@example.com> queued as 4a6c2b.5889c3198200
Oct 25 01:17:00 mail01 dma[4a6c2b.5889c3198200]: <ops@example.com> trying delivery
Oct 25 01:17:00 mail01 dma[4a6c2b.5889c3198200]: using smarthost (smtp.relay.internal:8025)
Oct 25 01:17:00 mail01 dma[4a6c2b.5889c3198200]: trying remote delivery to smtp.relay.internal [10.89.56.2] pref 0
Oct 25 01:17:00 mail01 dma[4a6c2b.5889c3198200]: Server greeting successfully completed
Oct 25 01:17:00 mail01 dma[4a6c2b.5889c3198200]:   Server supports STARTTLS
Oct 25 01:17:00 mail01 dma[4a6c2b.5889c3198200]:   Server supports LOGIN authentication
Oct 25 01:17:00 mail01 dma[4a6c2b.5889c3198200]: SSL initialization successful
Oct 25 01:17:00 mail01 dma[4a6c2b.5889c3198200]: using SMTP authentication for user admin
Oct 25 01:17:00 mail01 dma[4a6c2b.5889c3198200]: <ops@example.com> delivery successful

日志的两段 ID 规律:dma[短ID] 是注入阶段,dma[短ID.队列ID] 是投递阶段,按队列 ID 串联即可还原一封邮件的一生。

八、sendmail 兼容旗标速览

手册明确的兼容项,调用方无感但值得知道:

  • -A c:sendmail 兼容占位(忽略);
  • -L tag:自定义 syslog 标识符(兼容 sendmail 的 -L);
  • -O:占位(忽略);-o i 等价 -i,其余 -o 参数忽略;
  • -bp、-bq 见上文;-q 可带参数但被忽略;
  • -r sender 等价 -f sender。

九、退出码与错误信息

实测采集到的两种:

# dma -Z
invalid argument: `-Z'
(exit 64 —— 用法错误)

注入与队列操作互斥时(见第四节)同样立即报错退出。mailq 空队列、newaliases 成功等正常路径 exit 0。手册约定错误路径下 dma 不会吞掉报文——失败邮件要么留在队列、要么退回 postmaster,二选一。

十、排障实录:队列清不掉的三步定位法

真实复现 + 完整回显,按顺序执行即可解决「dma -q 无声无息但队列不减」的经典问题。

第一步:确认队列还在,且 -q 「假装」成功了

# dma -Dq
(无任何输出)
echo exit=$?   → exit=0
# mailq
ID	: 4a496d.58a74b63d200
From	: root@mail.example.net
To	: ops@example.com

退出码 0、无报错、队列原封不动——这不是 dma 的 bug,是队列文件锁。

第二步:找出持锁的残留投递进程

dma 投递失败(尤其对端不可达、TCP connect 挂起)时,后台投递子进程可能存活数分钟并持有 Q 文件的 flock;此后所有 -q 都会静默跳过这封邮件。进程表里一眼可见:

# ps -ef | grep dma | grep -v grep
mail     4285       1  0 01:23 ?  00:00:00 dma -f root@mail.example.net ops@example.com

第三步:清掉持锁进程,重试冲刷

# kill -9 4285
# dma -q
(静默完成)
# mailq
Mail queue is empty

对端中继侧确认信件补投到位(该测试信在接收端计数 +1,实测验证)。整个定位过程不需要重启任何东西——dma 本来就没有可重启的东西。

延伸:如何避免复现

  • 给 SMARTHOST 配置一个会快速拒绝(RST)而不是黑洞的地址;
  • 对不可达目标,宁可让它进队列等 cron 冲刷,也不要在脚本里手动循环重试;
  • 长时间挂起的 connect 本质是网络问题,防火墙 REJECT 与 DROP 的行为差异在这里会直接变成「队列卡 1 分钟还是卡 5 分钟」。

十一、命令速查卡

想做什么命令
发一封邮件printf '...' | sendmail 收件人
收件人从头域来... | dma -t
正文含孤立点... | dma -i 收件人
指定信封发件人dma -f 地址 收件人
只入队不投递dma -bq 收件人
查队列mailq(= dma -bp)
立即冲刷dma -q
前台调试冲刷dma -Dq
别名生效newaliases
看投递轨迹tail /var/log/mail.log
自定义日志标识dma -L 标识 ...

参考来源(查询日期:2026-10-25)