mikel / mail

A Really Ruby Mail Library
MIT License
3.63k stars 935 forks source link

Sanitizing invalid characters from to field #1363

Open jkhulme opened 5 years ago

jkhulme commented 5 years ago

We're using v2.7.1 of the mail gem with ruby 2.4.4

Some of our users are typoing their names - not their email addresses - in ways that are causing syntax errors when we try and send the email.

Here are some examples, one that works fine, and two different failing examples - names have been changed, but the typos have been kept the same

Working:

to = "\"Joe Bloggs\" <joe.bloggs@example.com>"
m = Mail.new
m.to = to
#<Mail::Message:92412660, Multipart: false, Headers: <To: "Joe Bloggs" <joe.bloggs@example.com>>>

Failure 1:

to = "\"Joe B\"log-gs\" <joe.bloggs@example.com>"
m = Mail.new
m.to = to
#<Mail::Message:92412660, Multipart: false, Headers: <To: "Joe B"log-gs" <joe.bloggs@example.com>>>

Falure 2:

to = "\"JOE BLOGGS\\\" <joe.bloggs@example.com>"
m = Mail.new
m.to = to
#<Mail::Message:92412660, Multipart: false, Headers: <To: "JOE BLOGGS\" <joe.bloggs@example.com>>>

When we try and send the failures we get the error:

Net::SMTPSyntaxError: 501 Syntax error in parameters
/app/vendor/ruby-2.4.4/lib/ruby/2.4.0/net/smtp.rb:969 in check_response
/app/vendor/ruby-2.4.4/lib/ruby/2.4.0/net/smtp.rb:937 in getok
/app/vendor/ruby-2.4.4/lib/ruby/2.4.0/net/smtp.rb:837 in mailfrom
/app/vendor/ruby-2.4.4/lib/ruby/2.4.0/net/smtp.rb:658 in send_message
/gems/mail-2.7.1/lib/mail/network/delivery_methods/smtp_connection.rb:54 in deliver!
/gems/mail-2.7.1/lib/mail/network/delivery_methods/smtp.rb:101 in block in deliver!
/app/vendor/ruby-2.4.4/lib/ruby/2.4.0/net/smtp.rb:519 in start
/gems/mail-2.7.1/lib/mail/network/delivery_methods/smtp.rb:109 in start_smtp_session
/gems/mail-2.7.1/lib/mail/network/delivery_methods/smtp.rb:100 in deliver!
/gems/mail-2.7.1/lib/mail/message.rb:276 in deliver!

I've tried to find out what the allowed characters in the to are, but I haven't been able to find it.

I'm wondering if there is something we could do escape the characters, I tried CGI.escape but it didn't seem to have the effect I wanted

"%22JOE+BLOGGS%5C%22+%3Cjoe.bloggs%40example.com%3E"
#<Mail::Message:92412660, Multipart: false, Headers: <To: %22JOE+BLOGGS%5C%22+%3Cjoe.bloggs%40example.com%3E>>

Any advice on how we could prevent the errors, and allow the emails to be sent correctly would be appreciated

barrettkingram commented 4 years ago

The rules here are quite complicated. You can read them in RFC5322 if you're interested.

But to summarize, in quoted names like you're using, you can use ASCII %d33-126, except for %d34 and %d92 (double quote and backslash). This is why your examples are having problems.

It is possible to escape those characters with a backslash. Maybe something like this would work for you?

email = "joe.bloggs@example.com"
name = "Joe B\"log-gs"
escaped_name = name.gsub(/\\/) { '\\\\' }.gsub(/"/) { '\"' }
to = "\"#{escaped_name}\" <#{email}>"

# Test this can be parsed:
Mail::AddressList.new(to)