Amavis 拒绝多部分/混合内容类型和边界

Amavis 拒绝多部分/混合内容类型和边界

我正在编写一个用于发送 SMTP 电子邮件的 Ruby 脚本。电子邮件分为 3 个部分:标题、正文和附件。不幸的是,我很难满足 Amavis 的要求:正确编写封装边界。

由 Amavis 添加的这个标题注意到了这个问题:

X-Amavis-Alert: BAD HEADER SECTION, MIME error: error: multipart boundary is missing, or contains CR or LF

我读过RFC 1341 第 7_2 节,它定义了多部分语法。

请注意,封装边界必须出现在行首,即 CRLF 之后,并且初始 CRLF 被视为封装边界的一部分,而不是前一部分的一部分。边界后面必须紧跟另一个 CRLF 和下一部分的标头字段,或者两个 CRLF,在这种情况下,下一部分没有标头字段(因此假定其为 Content-Type text/plain)。

  • 封装边界必须遵循 CRLF
  • 封装边界后面必须紧接着另一个 CRLF + 下一部分的标头字段

我相信我的脚本遵守了这两条规则,但是,有些邮件客户端无法识别附件。这是原始电子邮件(请注意,每个封装边界前面和后面都有一个 CRLF):

From: [email protected]\nTo: [email protected]\nSubject: =?UTF-8?B?RMOpY2xhcmF0aW9uIHNpbXBsaWZpw6llIGRlIHZpb2xlbmNl?=\nDate: 2020-12-17 15:59:14 +0100\nMIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=_3c7d2a21904930ec7ff47d0cb268c6605a8d06c02dc50e0c5498926371fae06a68d7\r\n--_3c7d2a21904930ec7ff47d0cb268c6605a8d06c02dc50e0c5498926371fae06a68d7\r\nContent-Type: text/html;charset=\"utf-8\"\nContent-Transfer-Encoding:utf8\r\n\nEMAIL BODY CONTENT HERE\r\n--_3c7d2a21904930ec7ff47d0cb268c6605a8d06c02dc50e0c5498926371fae06a68d7\r\nContent-Type: multipart/mixed; name = \"declaration_171220_155914166.pdf\"\nContent-Transfer-Encoding:base64\nContent-Disposition: attachment; filename = declaration_171220_155914166.pdf\n\nJVBERi0xLjMKJf///...(<- Base64 encoded attachment)...\r\n--_3c7d2a21904930ec7ff47d0cb268c6605a8d06c02dc50e0c5498926371fae06a68d7--

我做错了什么?您认为是什么阻止了不宽容的客户端显示附件?


如果它可以帮助任何人,这是我的 Ruby 脚本
require 'base64'

module Reports
  module SMTP
    BOUNDARY = '_3c7d2a21904930ec7ff47d0cb268c6605a8d06c02dc50e0c5498926371fae06a68d7'

    def self.send_report(file_path)
      file_content    = File.binread(file_path)
      encoded_content = [file_content].pack('m')   # Base64
      email_content   = headers + attachment(file_path, encoded_content) + body

      begin
        Net::SMTP.start('groupware.sdis21.org', 25, 'HELO FQDN', 'username', 'password', :plain) do |smtp|
          smtp.send_message(email_content, '[email protected]', ['[email protected]'])
        end
      rescue => e
        puts e.inspect, e.backtrace
      end
    end

    def self.headers
      <<~EOF
        From: [email protected]
        To: [email protected]
        Subject: =?UTF-8?B?#{Base64.strict_encode64('Déclaration simplifiée de violence')}?=
        Date: #{Time.now.to_s}
        MIME-Version: 1.0
        Content-Type: multipart/mixed; boundary=#{BOUNDARY}\r
        --#{BOUNDARY}\r
      EOF
    end

    def self.body
      <<~EOF
        Content-Type: text/html;charset="utf-8"
        Content-Transfer-Encoding:utf8

        EMAIL BODY CONTENT HERE\r
        --#{BOUNDARY}\r
      EOF
    end

    def self.attachment(file_path, encoded_content)
      file_path = file_path.split('/').last
      <<~EOF
        Content-Type: multipart/mixed; name = "#{file_path}"
        Content-Transfer-Encoding:base64
        Content-Disposition: attachment; filename = #{file_path}

        #{encoded_content}\r
        --#{BOUNDARY}--\r
      EOF
    end
  end
end

答案1

问题是我们使用的 Web 客户端需要Content-Type附件的正确标头:

Content-Type: application/pdf; name="filename.pdf"

为了弄清这一点,我查看了从 postfix 服务器 ( /var/spool/imap/our_domain/...) 收到的一些电子邮件,并将其与我使用脚本生成的原始电子邮件进行了比较。最明显的区别就是这个标题。

相关内容