nette / mail

A handy library for creating and sending emails in PHP
https://doc.nette.org/mailing
Other
469 stars 71 forks source link

UTF8 in attachment filename is not encoded #75

Closed tumapav closed 4 years ago

tumapav commented 4 years ago

Version: 3.1.4

Bug Description

If the attachment file name contains UTF8 characters, the header is not RFC 2047 encoded, which causes email to rely on support of SMTPUTF8 extension, making the email undeliverable to destinations servers that don't support it (gmail supports it, but e.g. email.cz does not).

Steps To Reproduce

$mail = new Nette\Mail\Message;
$mail->setFrom('John <john@example.com>')
        ->addTo('peter@example.com')
        ->setSubject('Kůň v příloze')
        ->setBody("Test")
        ->addAttachment("kůň.txt", "test");

die($mail->generateMessage());

See resulting Content-Disposition header:

Content-Disposition: attachment; filename="kůň.txt"

Expected Behavior

Content-Disposition: attachment; filename="=?UTF-8?B?a8WvxYgudHh0?="

Possible Solution

This worked in the previous version, the bug was introduced with this change https://github.com/nette/mail/commit/6f333738075ba9ee152795dcbbd84569127a3182 which fixed #24, in this change, call to encodeHeader() has been removed. This call should be probably returned, but I'm not sure how exactly in order to not introduce back the issue #24.

I know a workaround is not to use utf8 in attachment file name with e.g. Strings::toAscii($filename), but as long as the encoding works well with other headers like Subject or From, I don't see a reason for this header to be an exception.

milo commented 4 years ago

It is hard to find some RFC for such situation. So, to find some working solution, I use Thunderbird. So I sent attachment named jůůůžě.txt via Thunderbird and GMail SMTP and I got:

Content-Type: text/plain; charset=UTF-8;
 name="=?UTF-8?B?asWvxa/Fr8W+xJsudHh0?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename*=UTF-8''%6A%C5%AF%C5%AF%C5%AF%C5%BE%C4%9B%2E%74%78%74
milo commented 4 years ago

And this is via. GMail web interface:

Content-Type: text/plain; charset="UTF-8"; name="=?UTF-8?B?asWvxa/Fr8W+xJsudHh0?="
Content-Disposition: attachment; filename="=?UTF-8?B?asWvxa/Fr8W+xJsudHh0?="
Content-Transfer-Encoding: base64
Content-ID: <f_kfz6pkr50>
X-Attachment-Id: f_kfz6pkr50
dg commented 4 years ago

Milo, can you try to send files named ", \ and x? I am unable do it on Windows (except the third).

milo commented 4 years ago

Third char sould be x? I tried ů"\?x.txt and this is a result of Thunderbird 78.3.1 on Debian 10:

Content-Type: text/plain; charset=UTF-8;
 name="=?UTF-8?B?xa8iXD94LnR4dA==?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename*=UTF-8''%C5%AF%22%5C%3F%78%2E%74%78%74

Correctly seen as ů"\?x.txt attachment in Thunderbird on Windows and when trying to save it, Thunderbird replaces name to ů___x.txt.

milo commented 4 years ago

And how encoded by GMail webface:

Content-Type: text/plain; charset="US-ASCII"; name="=?UTF-8?B?xa8iXD94LnR4dA==?="
Content-Disposition: attachment; filename="=?UTF-8?B?xa8iXD94LnR4dA==?="
Content-Transfer-Encoding: base64
X-Attachment-Id: f_kfzgl8310
Content-ID: <f_kfzgl8310>
milo commented 4 years ago

When sending ".txt. Thunderbird

Content-Type: text/plain; charset=UTF-8;
 name="\".txt"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename="\".txt"

GMail

Content-Type: text/plain; charset="US-ASCII"; name="\".txt"
Content-Disposition: attachment; filename="\".txt"
Content-Transfer-Encoding: base64
Content-ID: <f_kfzgqenu0>
X-Attachment-Id: f_kfzgqenu0
dg commented 4 years ago

Thanks!

dg commented 4 years ago

Just to be sure, can you check also \ alone?

milo commented 4 years ago

Thunderbird "

Content-Type: text/plain; charset=UTF-8;
 name="\""
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename="\""

\

Content-Type: text/plain; charset=UTF-8;
 name="\\"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename="\\"
milo commented 4 years ago

And long ones (160 chars): 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 and ž23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789ž

in Thunderbird:

Content-Type: text/plain; charset=UTF-8;
 name="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename*0="123456789012345678901234567890123456789012345678901234567890";
 filename*1="123456789012345678901234567890123456789012345678901234567890";
 filename*2="1234567890123456789012345678901234567890"
Content-Type: text/plain; charset=UTF-8;
 name="=?UTF-8?Q?=c5=be2345678901234567890123456789012345678901234567890123?=
 =?UTF-8?Q?45678901234567890123456789012345678901234567890123456789012?=
 =?UTF-8?Q?34567890123456789012345678901234567890123456789=c5=be?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename*0*=UTF-8''%C5%BE%32%33%34%35%36%37%38%39%30%31%32%33%34%35%36%37;
 filename*1*=%38%39%30%31%32%33%34%35%36%37%38%39%30%31%32%33%34%35%36%37;
 filename*2*=%38%39%30%31%32%33%34%35%36%37%38%39%30%31%32%33%34%35%36%37;
 filename*3*=%38%39%30%31%32%33%34%35%36%37%38%39%30%31%32%33%34%35%36%37;
 filename*4*=%38%39%30%31%32%33%34%35%36%37%38%39%30%31%32%33%34%35%36%37;
 filename*5*=%38%39%30%31%32%33%34%35%36%37%38%39%30%31%32%33%34%35%36%37;
 filename*6*=%38%39%30%31%32%33%34%35%36%37%38%39%30%31%32%33%34%35%36%37;
 filename*7*=%38%39%30%31%32%33%34%35%36%37%38%39%30%31%32%33%34%35%36%37;
 filename*8*=%38%39%C5%BE

via GMail webface

Content-Type: application/octet-stream; 
    name=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Content-Disposition: attachment; 
    filename=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Content-Transfer-Encoding: base64
Content-ID: <f_kg0oa0110>
X-Attachment-Id: f_kg0oa0110
Content-Type: application/octet-stream; 
    name="=?UTF-8?Q?=C5=BE23456789012345678901234567890123456789012345678901234567?=
    =?UTF-8?Q?890123456789012345678901234567890123456789012345678901234567?=
    =?UTF-8?Q?890123456789012345678901234567890123456789=C5=BE?="
Content-Disposition: attachment; 
    filename="=?UTF-8?Q?=C5=BE23456789012345678901234567890123456789012345678901234567?=
    =?UTF-8?Q?890123456789012345678901234567890123456789012345678901234567?=
    =?UTF-8?Q?890123456789012345678901234567890123456789=C5=BE?="
Content-Transfer-Encoding: base64
Content-ID: <f_kg0oa04b1>
X-Attachment-Id: f_kg0oa04b1
dg commented 4 years ago

Thanks! Now it should work correctly