gen_smtp (latest) that sends a multipart/alternative email to an upstream mailserver.
Upstream mailserver applies DKIM and then forwards to final destination.
Until here all is good.
If the final destination is an Office365 mailserver that forwards to gmail, email is marked as spam by gmail.
So, in order to recap:
gen_stmp -> mailserver (dkim) -> Office365 ok
gen_stmp -> mailserver (dkim) -> Gmail ok
gen_stmp -> mailserver (dkim) -> Office365 -> Gmail not ok (mail detected as spam)
After investigating and comparing to other mail clients, we discovered that when encoding a multipart body an extra whiteline is added between the multipart/alternative component and the parts, for example
When Office365 forwards the email, it "cleans up" that empty line, resulting into the DKIM body signature no more valid, so Gmail mark it as spam.
Other clients do not add this extra empty line when composing multipart/mixed content.
The RFC is not very clear if it's allowed or not. Looking into the code the extra line is added here which should not be needed since encode_componentadds it already at the beginning of the component.
A quick test done by removing that extra line seems to fix the issue, but I'm not sure if it is correct or breaks something else.
Scenario:
gen_smtp (latest) that sends a multipart/alternative email to an upstream mailserver. Upstream mailserver applies DKIM and then forwards to final destination.
Until here all is good.
If the final destination is an Office365 mailserver that forwards to gmail, email is marked as spam by gmail.
So, in order to recap:
After investigating and comparing to other mail clients, we discovered that when encoding a multipart body an extra whiteline is added between the
multipart/alternative
component and the parts, for exampleWhen Office365 forwards the email, it "cleans up" that empty line, resulting into the DKIM body signature no more valid, so Gmail mark it as spam.
Other clients do not add this extra empty line when composing multipart/mixed content.
The RFC is not very clear if it's allowed or not. Looking into the code the extra line is added here which should not be needed since
encode_component
adds it already at the beginning of the component.A quick test done by removing that extra line seems to fix the issue, but I'm not sure if it is correct or breaks something else.