mikel / mikel/mail

Trouble with wrongly encoded non-ASCII filenames

Open
#651 6 comments 1 reaction 0 assignees View on GitHub
Bug Encoding Header Fields
Dominant language
Ruby
Stars
3.7k
Forks
934
PR merge metrics
No merged PRs in 30d

Description

If the filename in the Content-Disposition header of an attachment contains non-ASCII characters, then the following code fails with an error:

```
$ locale
LANG=en_US.utf8
LANGUAGE=
LC_CTYPE="en_US.utf8"
LC_NUMERIC="en_US.utf8"
LC_TIME="en_US.utf8"
LC_COLLATE="en_US.utf8"
LC_MONETARY="en_US.utf8"
LC_MESSAGES="en_US.utf8"
LC_PAPER="en_US.utf8"
LC_NAME="en_US.utf8"
LC_ADDRESS="en_US.utf8"
LC_TELEPHONE="en_US.utf8"
LC_MEASUREMENT="en_US.utf8"
LC_IDENTIFICATION="en_US.utf8"
LC_ALL=

$ irb
> require 'mail'
> Mail.new(File.new('/tmp/mail.txt').read).to_s
NoMethodError: undefined method `disposition_type' for #
from /home/clemens/.rvm/gems/ruby-2.0.0-p353@global/gems/mail-2.5.4/lib/mail/field.rb:167:in `method_missing'
from /home/clemens/.rvm/gems/ruby-2.0.0-p353@global/gems/mail-2.5.4/lib/mail/part.rb:37:in `inline?'
from /home/clemens/.rvm/gems/ruby-2.0.0-p353@global/gems/mail-2.5.4/lib/mail/part.rb:42:in `add_required_fields'
from /home/clemens/.rvm/gems/ruby-2.0.0-p353@global/gems/mail-2.5.4/lib/mail/message.rb:1788:in `ready_to_send!'
from /home/clemens/.rvm/gems/ruby-2.0.0-p353@global/gems/mail-2.5.4/lib/mail/message.rb:1786:in `block in ready_to_send!'
from /home/clemens/.rvm/gems/ruby-2.0.0-p353@global/gems/mail-2.5.4/lib/mail/message.rb:1784:in `each'
from /home/clemens/.rvm/gems/ruby-2.0.0-p353@global/gems/mail-2.5.4/lib/mail/message.rb:1784:in `ready_to_send!'
from /home/clemens/.rvm/gems/ruby-2.0.0-p353@global/gems/mail-2.5.4/lib/mail/message.rb:1800:in `encoded'
from /home/clemens/.rvm/gems/ruby-2.0.0-p353@global/gems/mail-2.5.4/lib/mail/message.rb:1869:in `to_s'
from (irb):2
from /home/clemens/.rvm/rubies/ruby-2.0.0-p353/bin/irb:12:in `'
```

Here is the used mail.txt:

```
Message-ID: <1234567890@test.test>
Date: Thu, 09 Jan 2014 00:00:00 +0100
From: Test
MIME-Version: 1.0
To: test@test.test
Subject: Test
Content-Type: multipart/mixed;
boundary="------------090202060701010202050308"

This is a multi-part message in MIME format.
--------------090202060701010202050308
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit

Test

--------------090202060701010202050308
Content-Type: image/png;
name="überraschung.png"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="überraschung.png"

iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQY02P8z8Dwn4EIwMRA
JBhVSB2FAD2cAhLPzm83AAAAAElFTkSuQmCC
--------------090202060701010202050308--
```

Normally, the filename parameter of the Content-Disposition header should be encoded as described in RFC 2183 and RFC 2184. But not all mail clients are doing this.

The following monkey patch solves the problem by replacing all non-ASCII characters in the Content-Disposition header:

```
module Mail
class ContentDispositionElement
def cleaned(string)
string = string.encode('US-ASCII', invalid: :replace, undef: :replace, replace: '_') unless string.ascii_only?
string =~ /(.+);\s*$/ ? $1 : string
end
end
end
```

(I can't use `Mail::Encodings.param_encode` in the `cleaned` method because `string` contains the whole header and not only the value of the filename parameter.)

I haven't created a pull request with tests, because I am not sure if the above solution is the correct way to handle this.

Contributor guide

Open the contributing guide

Research direction

Start at lib/mail/field.rb and follow the Content-Disposition handling into lib/mail/part.rb, where inline? triggers the reported failure. Reproduce the supplied multipart message, determine how non-ASCII filename parameters should be handled, and add regression coverage showing serialization completes without NoMethodError.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.