Newlines resolved as =0A in Sendgrid X-SMTPAPI header - ruby-on-rails

I am using Sendgrid to send email to a mailing list, using the X-SMTPAPI header to specify the multiple recipients. From the Sendgrid documentation "Headers must be wrapped to keep the line length under 72."
I am using the ActionMailer to send emails, and setting the X-SMTPAPI header using the headers method. To keep lines less than 72 characters, I have tried replacing each comma with a comma+newline+space. For example,
headers["X-SMTPAPI"] = {
:to => ['user1#example.com','user2#example.com','user3#example.com','user4#example.com','user5#example.com','user6#example.com']
}.to_json.gsub(',',",\n ")
Instead of getting newlines in my header, I am getting the following (from the log file)
X-SMTPAPI: {"to":["user1#example.com",=0A "user2#example.com",=0A "user3#example.com",=0A "user4#example.com",=0A "user5#example.com",=0A "user6#example.com"]}
Note that the \n characters are being replaced with =0A. This sequence is rejected as invalid by the Sendgrid server.
Any ideas what I can do to get the proper newlines into the header?
Edit:
I tried adding a "puts headers" to see what is being set in the headers. Then is what I found
Date: Sat, 13 Apr 2013 18:21:36 -0400
Message-ID: <5169da701cd26_5343fe1776afc50749b4#saunders.mail>
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
X-SMTPAPI: {"to":["user1#example.com",=0A "user2#example.com",=0A
"user3#example.com",=0A "user4#example.com",=0A "user5#example.com",=0A
"user6#example.com"]}
Note the newlines I am adding are still showing up as "=0A". But something appears to be adding wrapping on its own. Is this wrapping automatic, and sufficient to keep my header line length from exceeding the requirements?

ActionMailer actually will handle folding and encoding the lines for you if you give it the proper spacing to do so. You should use JSON.generate to give it the spacing:
Ex.
headers["X-SMTPAPI"] = JSON.generate({
:category => "welcome_email",
:to => ['user1#example.com','user2#example.com','user3#example.com','user4#example.com','user5#example.com','user6#example.com']
}, :indent => ' ')
Which would result in:
X-SMTPAPI: { "category":"welcome_email", "to":[ "user1#example.com",
"user2#example.com", "user3#example.com", "user4#example.com",
"user5#example.com", "user6#example.com"]}
As you can see, when ActionMailer encounters whitespace, it will wrap things for you - no need for the usual \r\n.

It seems like characters in headers have to be encoded according to the rules of RFC 2047 [14].
Accodingly to ASCII table %0A states for \n

Related

Rails 4/5 Sending Dynamic ActionMailer::Base.mail email With Attachment labeled Noname

I've taken a look at similar posts that mostly deal with sending an attachment by creating a view and controller, such as:
PDF attachment in email is called 'Noname'
but I've got a process that generates files in the background dynamically and need to attach it to a recipient list using ActionMailer::Base.mail. Below is the code:
def send_email(connection)
email = ActionMailer::Base.mail(to: connection['to'], from: connection['from'], subject: 'Sample File', body: "<p>Hello,</p><p>Your data is ready</p>", content_type: 'multipart/mixed')
email.cc = connection['cc'] if connection['cc'].present?
email.bcc = connection['bcc'] if connection['bcc'].present?
#files.each do |file|
report_file_name = "#{#start_time.strftime('%Y%M%dT%I%m%s')}_#{file[0]}.xlsx"
file_location = "#{Rails.root}/tmp/#{report_file_name}"
email.attachments[report_file_name] = File.open(file_location, 'rb'){|f| f.read}
end
email.deliver if email
end
I can see in the logs that it's sending with the content but assume it's sending as Noname because it can't find the view. Any way to get this to work successfully?
Below is the sample output:
Sent mail to sample#sample.com (383.9ms) Date:
Thu, 13 Oct 2016 08:47:30 -0400 From: Sample To:
Recipient Message-ID:
<57ff326270f15_421f1173954919e2#ulinux.mail> Subject: Sample File
Mime-Version: 1.0 Content-Type: multipart/mixed; charset=UTF-8
Content-Transfer-Encoding: 7bit
-- Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;
filename=20161012T08101476259208_Data.xlsx
Content-Transfer-Encoding: base64 Content-Disposition: attachment;
filename=20161012T08101476259208_Data.xlsx Content-ID:
<57ff326270f15_421f1173954919e2#ulinux.mail>
UEsDBBQAAAAIAO.. ... ...ADUFQAAAAA=
Update - I noticed if I use email.content_type = 'text/plain' - the attachment comes through successfully. For me, this works, though I'd appreciate later being able to style my emails with HTML
I presume this works because it prevents Rails from its usual gleaning/autointerpreting process. I'd certainly like to see a multipart/mixed or html compatible version work here though.
Update 2 This only fixed the issue artificially in the rails_email_preview gem, which renders the emails to a new tab in development. In production, this simply and understandably prints the details and the presumably base64-encoded file, so question remains open.
I have meet this problem too, after some investigation, it seems in Rails 4, you can't call attachments method after calling mail method, otherwise the content_type of the mail message object won't have boundary information so that the attachments part can't be parsed correctly in the received email.
I think digging into the actionmailer source code and you should be able to find a solution, either by override the default mail method or set the correct boundary info manually.
But for quick resolving this problem, I thought out a not elegant work around by using meta programming: define a delegation class which inherits ActionMailer::Base.
class AnyMailer < ActionMailer::Base
# a delegation mailer class used to eval dynamic mail action
end
Then eval this class with defining an arbitrary method to perform the email sending.
def send_email(connection, files)
AnyMailer.class_eval do
def any_mailer(connection, files)
files.each do |file|
report_file_name = :foo
file_location = :bar
attachments[report_file_name] = File.open(file_location, 'rb'){|f| f.read}
end
mail(to: connection['to'], from: connection['from'], subject: 'Sample File', body: "<p>Hello,</p><p>Your data is ready</p>")
end
end
AnyMailer.any_mailer(connection, files).deliver_now
end
Attention, you don't need to specify the content_type as 'multipart/mixed', ActionMailer will handle it correctly. I tried to specify it explicitly but get messed up email content instead.
This has been driving me insane.
Make sure you have a well formed .html template and a .text template if you are using mailer views.
Minimal errors in either of them will render the entire email as a noname attachment.
You might don't have mailer.text.erb file along with mailer.html.erb file.
Add it and your mail will be multipart.

MIME mail is not showing some pdf and .doc attachments

Hello this is my first post on this site.
Now i encountered a strange problem with MIME. I am working on writing emlx mail files.
(objective c, cocoa)
now i have no problem with showing images in mails. the problems is that half of my .doc and pdf attachments don't show in the message.
An formatting example.
MessageLength in Bytes(i.e 8556)
From: some#email
To: some#email2
Subject: mailsubject
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="somerandomgeneratedstring"
--somerandomgeneratedstring
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Body Text(not html body)
--somerandomgeneratedstring
Content-Type: application/msword; name="somefile.doc"
Content-Disposition: attachment; filename="somefile.doc"
Content-Transfer-Encoding: base64
[base64 encoded data]
--somerandomgeneratedstring--
PlistStructure
The text body is always displayed properly. The problem is that some text file attachments like .doc and pdf are not displayed, i run the same code for multiple text files and some work and some do not i have no clue why. all pictures work.
The thing i don't get is if i use the same data that wont work for MIME and write is as a file to my desktop the file is displayed properly.
Is there something i am missing ? Is there something i have to take care of when encoding such files in base64 ? if so why do some files work and others dont ?(source is in binary format, i encode is using nsdata base64encoding in Xcode)
I have gone trough the mime documentation multiple times and i cant seem so find a solution.
Can anyone please give me some tips or suggestions ?
EDIT: omg i forgot about this, The problem was that i had a problem with the first line, length in bytes, after i fixed that it worked. Sorry for wasting time :(
You need to get rid of the blank line between the top-level MIME-Version and Content-Type headers. MIME headers and body are separated by a blank line, so your Content-Type is effectively ignored as a header and treated as body content instead.
From: some#email
To: some#email2
Subject: mailsubject
MIME-Version: 1.0
<-- get rid of this blank line
Content-Type: multipart/mixed; boundary="somerandomgeneratedstring"
Update: since this problem is not a factor anymore, the only remaining factor you have not shown yet is the actual base64 data. It is likely malformed in some way that is preventing proper decoding. Everything else you have shown is accurate.

Sending 1 attachement, recipients reports 2 attachements (ATT0001.c added) - Rails 3, ActionMailer

To exchange data with another system we send the data as an email attachment to a dedicated address. The email is generated using ActionMailer v3.2.12.
The problem is that when the email arrives at its destination, a redundant attachment named ATT00001.c is a part of the email, in addition to the attachment we created. This causes issues with the import routine at the other end.
A big part of the problem is that we know almost nothing about how the email is being handled at the destination . We also dont know what type of email server is in use and dont have access to check what the email actually looks like when it arrives. We can send it to one of our own addresses and it looks fine there.
I know this is not a lot to go on, but perhaps one of you guys have seen these ATT00001-attachments being added to machine generated emails before.
config.action_mailer.smtp_settings
address: smtp.<mailprovider>.com
port: 587
domain: ourdomain.com
authentication: login
user_name: <removed>
password: <removed>
enable_starttls_auto: false
Update:
We've been able to obtain a copy of the problematic email and it shows the email body rendered after the attachment as an attachment of its own.
We've tried setting ActionMailer's parts_order to make sure the attachment is generated after the email body, it did not help.
Update2:
Sending to my gmail account and showing original raw data I get this.
SENT MAIL
in receipt response from recipient to the correct attachment (the autocreated one creates an error log entry)
(...) cut: to from and through email header information
Mime-Version: 1.0
Content-Type: multipart/mixed;
charset=UTF-8
Content-Transfer-Encoding: 7bit
--
Date: Thu, 28 Feb 2013 12:15:23 +0100
Mime-Version: 1.0
Content-Type: text/plain;
charset=UTF-8
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="thefile.mscons"
Content-ID: <512f3c4b6e875_a8f756dcc642fe#bjorns_arch.mail>
VU5BOisuPyAnVU5CK1VOT0M6Mys3MDgwMDAzNDExNzE2OjE0OlRJTUVSKzcw
... many more lines like this ...
ODAwMDUwNTEyMTc6MTQ6VElNRVIrMTMwMjI4OjEyMTUrUE9XRVNUMTMwMjI4
----
This is with body nil in actionmailer
Next is a RESPONSE from the recipient system, sent to my gmail. It's a receipt on the correct attachment (the extra attachement generates an error, flushing their system)
RECEIVED MAIL
(..) unintersting header stuff with addresses
Content-Disposition: attachment;
filename="afilename.txt"
Content-Transfer-Encoding: base64
Content-Type: Application/EDIFACT; charset="iso-8859-1"
Mime-Version: 1.0
Date: Sat, 16 Feb 2013 11:07:10 +0100
From: ediel#example.com
To: ***#gmail.com
Subject: thesubject
Message-ID: <511f5a53.850a700a.2fa0.2a0eSMTPIN_ADDED_BROKEN#mx.google.com>
X-TM-AS-Product-Ver: IMSS-7.0.0.6298-6.8.0.1017-19380.002
X-TM-AS-User-Approved-Sender: Yes
X-Greylist: Sender is SPF-compliant, not delayed by
milter-greylist-4.0 (isp-app27-vm.isp.example.com [213.239.116.46]);
Sat, 16 Feb 2013 11:07:11 +0100 (CET)
X-ExampleIKT-MailScanner-Information: Please contact the ISP for more information
X-ExampleIKT-MailScanner-ID: r1GA7BqD021150
X-ExampleIKT-MailScanner: Found to be clean
X-ExampleIKT-MailScanner-From: ediel#example.com
X-Spam-Status: No
VU5BOisuPyAnVU5CK1VOT0M6Mys3MDgwMDA1MDUxMjE3OjE0OlRJTUVSKzcwODAwMDM0MTE3MTY6
.. more..
pUSU1FUisxJ1VOVCszKzEnVU5aKzErMjAxMzAyMDAyNDg1Nzcn
something suspicious with the Content-Type? Is a new (empty) attachment generated from the stuff prior to -- in the sent email?
I believe this is to do with inline attachments and Exchange server. Some clients, Apple Mail in particular allow you to add inline attachments, that is, a MIME attachment sandwiched in between text/body parts of an email. Exchange server expects that all attachments appear after any text portion of a mail.
Everything after the attachment in your mail gets treated as an attachment, so the body gets stuffed into a file and named as you reported it to be named. Seeing as you're using ActionMailer, see this answer and possible this answer, which explains that you need to switch the order of the lines of code, and possibly play with some other settings.
Our problem is solved, though unfortunately I cant say what caused the redundant attachment. We worked around it by sending a non-multipart email that contained only the attachment. This solution obviously wont work for people who need to send a multipart email.
Sending non-multipart email with an attachment in Rails is not straight forward. You cant use the attachment helper method and a blank body, you need to put the attachment content in the email body and manually specify the disposition.
class MailMan < ActionMailer::Base
def test
attachment_content = "my attachment"
disposition = "attachment; filename=\"test.txt\""
mail(body: attachment_content, content_disposition: disposition)
end
end

Sending email with attachments

I've got a mailer that as follows:
class Payments::LateNoticesMailer < AsyncMailer
def notice(payment_id)
#payment = PaymentDecorator.find(payment_id)
#invoice = #payment.invoice
template = "payments/invoices/#{#payment.made_with_type.downcase}/show"
attachments["#{#payment.invoice_filename}.pdf"] =
WickedPdf.new.pdf_from_string( render_to_string( pdf: #payment.invoice_filename,
formats: [:pdf],
template: template,
layout: "layouts/pdf.html"))
mail to: #payment.payer_email,
from: '"RentingSmart" <no-reply#rentingsmart.com>',
cc: #payment.landlord_email,
subject: "*** Your rent payment of #{#payment.amount_due} is overdue ***"
end
end
which I send using SendGrid. Here's my issue, if I open up the email via Gmail, everything works great, the text of the email is there, and the attachment is attached. However, if I open it up using OSX's Mail.app or on my iPhone, I simply get the following:
This is a multi-part message in MIME format...
Anybody have any tips? I think I am following the Rails guides correctly.
Here is the call that I make Payments::LateNoticesMailer.notice(payment.id).deliver
According to the api docs for ActionMailer::Base, if multiple template types are used, all of them are rendered and the mime-type is automatically set to multipart/alternative.
If you add an attachment, the attachment is placed inside a multipart/mixed container.
First question: Are you rendering other types such as text and html? I would not recommend sending out emails with just a pdf part. Even if the text and html parts simply instruct the recipient to open the attachment, they should be there. Ideally, there would be more information in the text/html parts.
Second, are you trying to view the pdf inline, and not as an attachment?
Can you take a look at the raw source of the email and update your post with the structure you're seeing? There will be an initial mime type set in the header. it will look something like this:
Mime-Version: 1.0
Content-Type: multipart/mixed;
boundary="--==_mimepart_50596418be947_c7223fec9d834d3874256";
charset=UTF-8
Content-Transfer-Encoding: 7bit
This says the parts to follow are not alternative versions of the same information, but instead instruct the email client to display them distinctly.
Later on in the email, your text and html parts should proceeded by something like:
----==_mimepart_50596418be947_c7223fec9d834d3874256
Date: Wed, 19 Sep 2012 06:20:12 +0000
Mime-Version: 1.0
Content-Type: multipart/alternative;
boundary="--==_mimepart_50596418be468_c7223fec9d834d38741a5";
charset=UTF-8
Content-Transfer-Encoding: 7bit
And finally, the encoded pdf part should have a mime header like:
----==_mimepart_50596418be947_c7223fec9d834d3874256
Date: Wed, 19 Sep 2012 06:20:12 +0000
Mime-Version: 1.0
Content-Type: application/pdf;
charset=UTF-8;
filename=terms.pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename=terms.pdf
With a simple test email I just sent to myself with text, html parts, and a large pdf, I can view the email on my iphone. It shows the html part and an icon that lets me download the pdf.
Some e-mail clients may require an e-mail to have a plain text part in order to display it correctly.
I just ran into this message while converting a Rails app from 2.3 to 3.2. I thought I converted my mailer correctly, but the old version specified content_type: "multipart/mixed" in the options. However, when I removed that, I received the attachments and the HTML and plain-text rendered correctly. I think that having that setting in there overrode whatever Rails does to put in different types of content, which was not what I wanted. Thanks to the original answer for leading me in that direction.

ActionMailer - limit on number of recipients?

I've got Capistrano set up to send emails after deploying my RoR (2.3.8) application. I have a config/cap_mailer.rb file that basically looks like:
ActionMailer::Base.smtp_settings = {
:address => my,
:port => exchange,
:domain => server,
:authentication => settings,
:user_name => are,
:password => here
}
class CapMailer < ActionMailer::Base
def deploy_notification(cap_vars)
recipients cap_vars[:notify_emails]
from 'deploy#my.org'
subject "New app!"
body "Deployed application...blah blah blah"
end
end
Then, in my deploy.rb file, I have the following:
require 'config/cap_mailer.rb'
...
desc "Email recipients of deployment"
task :notify do
puts " * Sending notification email"
set :notify_emails, ["test1#my.org", "test2#my.org", etc.]
CapMailer.deliver_deploy_notification(self)
end
Now this all works fine and dandy......until I put more than 7 email addresses in the :notify_emails array. Up to 7 works fine, but when I put 8 or more (all valid addresses), the email gets screwed up a little bit (still goes through to the first 7, at least). Looking at the email header, it shows that it is cutting off the 8th (and 9th, 10th, ...) address from the 'To:' and putting it in the message body.
HEADER:
thread-index: AcyaZxlga08L9p35QYKJ22aiGG2zeA==
Content-Class: urn:content-classes:message
Importance: normal
Priority: normal
X-MimeOLE: Produced By ...
Received: from exchange.my.org ([ip address]) by ...; Thu, 3 Nov 2011 14:28:08 -0600
Date: Thu, 3 Nov 2011 14:28:08 -0600
From: deploy#my.org
To: test1#my.org,
test2#my.org,
test3#my.org,
test4#my.org,
test5#my.org,
test6#my.org,
test7#my.org
HEADER:
BODY:
test8#my.org
Message-Id:
<4eb2f95816341_135ff800c21ac130#my_box.local.tmail>
Subject: New app!
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8
Return-Path: deploy#my.org
X-OriginalArrivalTime: 03 Nov 2011 20:28:08.0494 (UTC)
FILETIME=[19601CE0:01CC9A67]
Deployed application...blah blah blah
BODY:
In addition, the subject does not appear on the email, even though the "error text" in the message body shows the correct subject.
Does anyone have any idea why this is happening? What is it about having 8 or more recipients that breaks it? I've Googled around and can't find anything about ActionMailer having a limit on the number of recipients (even if there were, that's a small limit). Is there something I'm missing? Any help is appreciated! I really need to be able to send to 8 or more recipients.
UPDATE: Setting the recipients directly with an array of 8 or more addresses still breaks things, so this clearly seems like a problem with ActionMailer and not Capistrano.
recipients ["test1#my.org", "test2#my.org", "test3#my.org", "test4#my.org",
"test5#my.org", "test6#my.org", "test7#my.org", "test8#my.org", "test9#my.org"]
The 7th email address is not followed by a comma, which could be the problem. Try passing a string to recipients, like cap_vars[:notify_emails].join(','), with no newlines.
Try passing a string to recipients without commas (there have been reports of commas as a problem), like:
cap_vars[:notify_emails].join(' ')
With all respect some simple things that you might overlook in debugging difficult errors:
If its mail server related install it on another production server? If you not sure it is the mail server acting up looking for another error may be of no help.
Try upgrade rails / ruby ? Perhaps its a bug in the code

Resources