
Estoy escribiendo un script Ruby que envía correos electrónicos SMTP. El correo electrónico se divide en 3 partes: encabezados, cuerpo y archivo adjunto. Desafortunadamente, estoy luchando por satisfacer un requisito de Amavis: escribir correctamente el límite de encapsulación.
Este encabezado, agregado por Amavis, notó el problema:
X-Amavis-Alert: BAD HEADER SECTION, MIME error: error: multipart boundary is missing, or contains CR or LF
He leído elsección 7_2 del RFC 1341, que define la sintaxis multiparte.
Tenga en cuenta que el límite de encapsulación debe ocurrir al comienzo de una línea, es decir, después de un CRLF, y que ese CRLF inicial se considera parte del límite de encapsulación en lugar de parte de la parte anterior. El límite debe ir seguido inmediatamente de otro CRLF y los campos de encabezado para la siguiente parte, o de dos CRLF, en cuyo caso no hay campos de encabezado para la siguiente parte (y, por lo tanto, se supone que es de tipo contenido texto/ plano).
- El límite de encapsulación debe seguir un CRLF.
- El límite de encapsulación debe ser seguido inmediatamente por otro CRLF + los campos de encabezado de la siguiente parte.
Creo que mi script respeta estas dos reglas; sin embargo, algunos clientes de correo no reconocen el archivo adjunto. Aquí está el correo electrónico sin formato (tenga en cuenta que los límites de cada encapsulación están precedidos y seguidos por un 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--
Qué estoy haciendo mal ? ¿Qué crees que impide que los clientes intolerantes muestren el archivo adjunto?
Si puede ayudar a alguien, aquí está mi script 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
Respuesta1
El problema fue que el cliente web que estamos usando espera un Content-Type
encabezado correcto para el archivo adjunto:
Content-Type: application/pdf; name="filename.pdf"
Para resolver esto, miré algunos correos electrónicos que recibí del servidor Postfix ( /var/spool/imap/our_domain/...
) y los comparé con el correo electrónico sin procesar que estoy produciendo con mi script. La diferencia más notable fue este encabezado.