
我正在編寫一個發送 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/清楚的)。
- 封裝邊界必須遵循 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
問題是我們使用的網路客戶端期望Content-Type
附件有正確的標頭:
Content-Type: application/pdf; name="filename.pdf"
為了弄清楚這一點,我查看了從 postfix 伺服器 ( /var/spool/imap/our_domain/...
) 收到的一些電子郵件,並將其與我使用腳本生成的原始電子郵件進行了比較。最明顯的區別是這個標題。