You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对接Postfix的non_smtp_milter以实现自定义DKIM签名?

如何对接Postfix的non_smtp_milter以实现自定义DKIM签名?

兄弟,太懂你折腾OpenDKIM碰壁的憋屈了——DKIM明明是邮件投递的命根子,找个顺手的现成工具咋就这么难!不过你已经摸到了Postfix的non_smtp_milters配置和OpenSSL的签名能力,其实已经站在起跑线上了,我给你捋个实操的入手方向,尽量贴合你偏好的bash方案:

首先得敲个重点:non_smtp_milters是基于Sendmail的Milter协议的,Postfix只是兼容这个接口,不是随便绑定个端口传数据就行的,你的程序得遵循Milter的通信规则来解析Postfix发过来的邮件数据,再返回处理后的结果。

先给你一个bash方向的起步方案

纯bash写Milter服务确实有点挑战(因为要处理二进制协议),但可以用socat这个工具来搭个桥梁,帮你监听端口、转发数据流,你只需要专注在邮件签名的逻辑上:

  1. 用socat绑定端口,对接Postfix和你的脚本
    先安装socat(大部分发行版的包管理器里都有),然后用下面的命令启动监听:

    socat TCP-LISTEN:8891,fork EXEC:/path/to/your/dkim-sign-script.sh
    

    这个命令会让socat监听本地8891端口,每收到Postfix的Milter请求,就启动你的bash脚本,把Milter的数据流通过标准输入/输出传递给脚本处理。

  2. 在bash脚本里处理Milter协议的基础逻辑
    Milter的消息是固定格式的:开头4字节是网络字节序的消息长度,后面是实际的消息内容。你的脚本首先得能读取并解析这个:

    # 读取4字节的长度字段(忽略dd的错误输出)
    len_bytes=$(dd bs=4 count=1 2>/dev/null)
    # 把二进制长度转成十进制(网络字节序转主机字节序)
    len=$(echo -n "$len_bytes" | od -An -tu4 -N4 | tr -d ' ')
    # 读取对应长度的消息内容
    msg=$(dd bs="$len" count=1 2>/dev/null)
    

    这里用了dd读二进制数据,od做格式转换,纯bash搞二进制确实有点绕,但凑合用是没问题的。

  3. 提取邮件内容,生成DKIM签名
    接下来你要从Milter消息里提取邮件的头和正文,然后按照DKIM的规范对内容做规范化处理:

    • 邮件头:要挑选DKIM要求的字段(比如From、To、Date、Subject等),按特定顺序排列,去掉多余的空格和换行
    • 邮件正文:要统一换行格式(比如把CRLF转成LF),去掉末尾的空白行
      然后用你熟悉的OpenSSL命令生成签名:
    # 生成正文的SHA256哈希(DKIM的bh字段)
    body_hash=$(echo -n "$normalized_body" | openssl dgst -sha256 -binary | base64)
    # 生成要签名的DKIM原始内容(头字段+正文哈希)
    dkim_data="$normalized_headers||$body_hash"
    # 用私钥签名,生成b字段
    dkim_signature=$(echo -n "$dkim_data" | openssl dgst -sha256 -sign /path/to/your/private.key | base64)
    

    最后把这些字段拼成标准的DKIM-Signature头:

    DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=yourdomain.com; s=your_selector; h=From:To:Date; bh=$body_hash; b=$dkim_signature
    
  4. 把签名头插回邮件,返回给Postfix
    按照Milter协议,你需要用ADDHEADER命令把生成的DKIM头插入到邮件里,然后返回“继续处理”的指令给Postfix。这部分需要你按照Milter的消息格式构造响应,再输出到标准输出(socat会把它传给Postfix)。

一些实用的注意事项

  • 纯bash处理Milter的二进制协议容易踩坑,比如邮件的编码、多部分邮件的处理、协议消息的错误处理等。如果遇到瓶颈,可以考虑用Python/Perl写个轻量的Milter服务,然后在服务里调用你的bash签名脚本,这样兼顾bash的灵活性和脚本语言处理协议的便利性。
  • 测试的时候,先把Postfix的non_smtp_milters配置改成inet:localhost:8891,重启Postfix后发测试邮件,然后看/var/log/mail.log(或者/var/log/maillog)里的Milter相关日志,检查有没有错误,同时查看收到的邮件头里有没有生成的DKIM签名。
  • 一定要严格遵循DKIM的规范来生成签名,比如头字段的顺序、空白的处理、签名的编码,不然签名会验证失败。

备注:内容来源于stack exchange,提问作者user10709800

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.16 10:03:03