
Ich schreibe ein Ruby-Skript, das SMTP-E-Mails sendet. Die E-Mail ist in drei Teile unterteilt: Kopfzeilen, Text und Anhang. Leider habe ich Probleme, eine Amavis-Anforderung zu erfüllen: die Kapselungsgrenze richtig zu schreiben.
In dieser von Amavis hinzugefügten Kopfzeile wurde das Problem festgestellt:
X-Amavis-Alert: BAD HEADER SECTION, MIME error: error: multipart boundary is missing, or contains CR or LF
Ich habe gelesenAbschnitt 7_2 des RFC 1341, das die mehrteilige Syntax definiert.
Beachten Sie, dass die Kapselungsgrenze am Anfang einer Zeile stehen muss, also nach einem CRLF, und dass dieses anfängliche CRLF als Teil der Kapselungsgrenze und nicht als Teil des vorhergehenden Teils betrachtet wird. Auf die Grenze müssen unmittelbar entweder ein weiteres CRLF und die Headerfelder für den nächsten Teil oder zwei CRLFs folgen, in welchem Fall es keine Headerfelder für den nächsten Teil gibt (und daher davon ausgegangen wird, dass es sich um den Inhaltstyp text/plain handelt).
- Die Kapselungsgrenze muss einem CRLF folgen
- Auf die Kapselungsgrenze muss unmittelbar ein weiteres CRLF + die Headerfelder des nächsten Teils folgen
Ich glaube, mein Skript beachtet diese beiden Regeln, allerdings erkennen einige Mail-Clients den Anhang nicht. Hier ist die Roh-E-Mail (beachten Sie, dass jeder Kapselungsgrenze ein CRLF vorangestellt und nachgestellt wird):
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--
Was mache ich falsch? Was hindert Ihrer Meinung nach intolerante Clients daran, den Anhang anzuzeigen?
Falls es jemandem helfen kann, hier ist mein Ruby-Skript
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
Antwort1
Content-Type
Das Problem bestand darin, dass der von uns verwendete Webclient einen korrekten Header für den Anhang erwartet :
Content-Type: application/pdf; name="filename.pdf"
Um das herauszufinden, habe ich mir einige E-Mails angesehen, die ich vom Postfix-Server ( /var/spool/imap/our_domain/...
) erhalten habe, und sie mit der Roh-E-Mail verglichen, die ich mit meinem Skript erstelle. Der auffälligste Unterschied war dieser Header.