In a Rails 5.1 ActionMailer, I want to attach a Mail object to an e-mail:
def attach_mail(original_email)
attachments['original-email.eml'] = { mime_type: 'message/rfc822', encoding: '7bit', content: original_email.to_s }
mail to: 'postmaster', subject: 'mail should be attached'
end
However, this does not produce valid e-mails. Thunderbird lists the attachment with size '0'. Horde lists the attachment with correct size, but does not recognize it as an e-mail.
I've tried variations of the attachments line:
attachments['original-email.eml'] = original_email
attachments['original-email.eml'] = { content: original_email.to_s }
attachments['original-email.eml'] = { mime_type: 'message/rfc822', content: original_email.to_s }
but none of these result in an e-mail with an e-mail attachment.
What's the solution?
Finally figured it out.
To attach an email (Mail object from the 'mail' gem) to an ActionMailer message, you need to specify the MIME type and encoding like so:
def attach_mail(original_email)
attachments['original-email.eml'] = { mime_type: 'message/rfc822',
encoding: '7bit',
content: original_email.to_s }
mail to: 'postmaster', subject: 'mail should be attached'
end
This creates a multipart/mixed message which is properly displayed in MUAs.
However, if you happen to add any inline attachment (e.g. to display a logo image in the ActionMailer e-mail body), the entire message will have a multipart/related mime type. The MUAs that I tried were unable to interpret a multipart/related message with an e-mail attachment.
Therefore, refrain from adding any inline attachments when attaching an e-mail to an e-mail.
Related
I am trying to send S3 url file in mail body, but I am getting error
Errno::ENOENT: No such file or directory # rb_sysopen
I want something like this, but I am unable to achieve this one
#path = s3_url
attachments["output.pdf"] = {
mime_type: "application/pdf",
content: HTTParty.get(#path).response.try(:body)
}
mail(to: 'xyz#gmail.com', subject: "Test Attchment", body: File.read(URI.parse(#path)))
Fetch the PDF using Net::HTTP or HTTPary and read the response to set the attachment in the mailer.
Try it this way:
# change the file name if required
mail.attachments["output.pdf"] = {
mime_type: "application/pdf",
content: HTTParty.get(s3_path).response.try(:body)
}
I'm working with SendGrid support to determine why categories stopped working on my multipart email campaigns (the text-only one is fine). If I intentionally set the content-type of an HTML email as "text/plain" the email displays the header data, text and raw html all on a single email, but will get its category. Otherwise the email looks correct, but there's no category.
SendGrid has asked me to send them a copy of the payload and I'm not sure what that is or how to find it. They said "If you are familiar with running a telnet test then that is what we are looking for." I'm not familiar with telnet tests. This is the info from the screenshot they provided as an example of what they're looking for:
220 Hi! This is Rob's hMailServer!
ehlo panoply-tech.com
250-SAGE013963
250-SIZE 20480000
250 AUTH LOGIN PLAIN
AUTH LOGIN
334 VXN1ea5bbVUG
YT3TQBHbhM9WBHKTDGUjeD65WQ20=
235 authenticated.
MAIL FROM: mayes#panoply-tech.com
250 OK
RCPT TO: cstickings#demosagecrm.com
250 OK
DATA
354 OK, send.
Subject: This is a test email
Hi Clemence,
Just sending you a test email.
.
250 Queued <25.927 seconds>
I went to .rvm/gems/ruby-2.3.3/gems/actionmailer-4.2.8/lib/action_mailer/base.rb and found a method called "set_payload_for_mail" but what that produces does seem to be like their example:
{"mailer":"B2c::B2cSendGridMailer",
"message_id":"5d0b979767c26_16f2c3fc04043f9c84968e#Domain-Person.local.mail",
"subject":"TEST: 26_txt","to":["person#domain.com"],
"from":["info#another.com"],"date":"2019-06-20T09:26:31.000-05:00",
"mail":"Date: Thu, 20 Jun 2019 09:26:31 -0500\r\nFrom: info#another.com\r\nTo: person#domain.com\r\nMessage-ID: \u003c5d0b979767c26_16f2c3fc04043f9c84968e#Domain-Person.local.mail\u003e\r\nSubject: TEST: 26_txt\r\nMime-Version: 1.0\r\nContent-Type: text/plain;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n
X-SMTPAPI: {\"category\":[\"html_false\"]}\r\n
X-SMTPAPI: {\"filters\": {\"ganalytics\": {\"settings\": {\"enable\":1}}}}
\r\n\r\nHi there, but text\r\n"}
I know in the Google inbox, you can click "Show Original" for an email and see the header info, etc. I've sent that to them but that didn't have what they needed.
def b2c_tester(html=false, content)
e_domain = 'careinhomes.com'
#mailer_path = "app/views/b2c/b2c_send_grid_mailer"
#from = "info#careinhomes.com"
#recipients = ['gina#pipelinesuccess.com']
#subject = html ? "#{DateTime.now.minute.to_s}_html" :
"#{DateTime.now.minute.to_s}_txt"
header_category = {"category": ["html_#{html}"]}
headers['X-SMTPAPI'] = header_category.to_json
if html
msg = tester_mail_with_opts({domain: e_domain}, content)
else
msg = tester_mail_plain_text_with_opts(
"b2c_tester",{domain: e_domain})
end
msg
end
#content ex: 'text/plain', 'text/html', 'multipart/alternative', etc
def tester_mail_with_opts(delivery_options={}, content=nil)
mail_opts = set_mail_opts(delivery_options)
unless content.nil?
mail_opts[:content_type] = content
end
mail mail_opts
end
def set_mail_opts(delivery_options={})
#subject = "TEST: #{#subject}" unless Rails.env.production?
# Required
mail_opts = {
to: #recipients,
from: #from,
subject: #subject,
}
mail_opts[:template_path] = #template_path if #template_path
mail_opts[:content_type] = #content_type if #content_type
# Do delivery options
mail_opts[:delivery_method_options] = DELIVERY_OPTIONS
mail_opts[:delivery_method_options] =
mail_opts[:delivery_method_options].merge(delivery_options)
unless delivery_options.blank?
mail_opts
end
In ActionMailer's base model is a method called deliver_mail that extracts the payload and you can capture it that way. It appears that, for my problem, the payload is an empty hash.
This is what a healthy payload should look like from ActionMailer:
{"mailer":"B2c::B2cSendGridMailer","message_id":"5d10dacb26dc2_17fb93ff52483b9c8952bf#Domain-Person.local.mail","subject":"TEST: 14_txt","to":["person#domain.com"],"from":["info#another.com"],"date":"2019-06-24T09:14:35.000-05:00","mail":"Date: Mon, 24 Jun 2019 09:14:35 -0500\r\nFrom: info#another.com\r\nTo: person#domain.com\r\nMessage-ID: \u003c5d10dacb26dc2_17fb93ff52483b9c8952bf#Domain-Person.local.mail\u003e\r\nSubject: TEST: 14_txt\r\nMime-Version: 1.0\r\nContent-Type: text/plain;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\nX-SMTPAPI: {\"category\":[\"html_false\"]}\r\nX-SMTPAPI: {\"filters\": {\"ganalytics\": {\"settings\": {\"enable\":1}}}}\r\n\r\nHi there, but text\r\n"}
Emails without attachment are delivered fine, but when there is an attachment I get boundary missing error on mandril:
{
"code": -98,
"name": "ValidationError",
"message": "Invalid raw_message: Bad multipart message - no boundary"
}
Letter opener in dev model shows the email rendering perfectly
The Email is html (rendered via Mandrill without a problem) and will have a PDF attachment.
the call to mailer is:
# template variables
merge_vars = {"AMOUNT" => "100"}
invoice = Invoice.new(customer)
attachments[invoice.name] = {
data: invoice.invoice_data,
mime_type: 'application/pdf'
}
content_type = "multipart/mixed"
mail(to: user.email, cc: cc_emails.compact.uniq, subject: mail_subject, content_type: content_type) do |format|
# Template renders fine
format.html{mandrill_template('invoice_template', merge_vars)}
end
Mandril gem version 1.0.53 and Rails 4.1.10.
I'm trying to send a file attachment using Rubys ActionMailer. However, when I send my file, the carriage returns "\r" that I've added are removed.
string = "the quick brown\r\nfox jumped over\r\nthe bridge"
File.open(file = "attachment_#{Time.now.to_i}.txt", "w+") do |f|
f.write(string)
end
attachments['test_file.txt'] = {
mime_type: 'text/plain',
content: string
}
mail(
:to => 'somebody#example.com',
:from => 'somebody#example.com',
:subject => 'Message Test'
).deliver
The file that is written has the proper line endings, but the attached file has the carriage returns removed. How I can prevent this from happening?
So just wanted to post my solution in case anyone else ends up with this issue...
After checking the base64 encoded attachment from the email, I found that the string, did in fact, not have the carriage return.
1.9.3-p448 :001 > Base64.decode64('dGhlIHF1aWNrIGJyb3duCmZveCBqdW1wZWQgb3Zlcgp0aGUgYnJpZGdlCg==')
=> "the quick brown\nfox jumped over\nthe bridge\n"
This led me to believe that the ActionMailer was in fact reformatting my email before it was encoded. I figured that I could just encode the message body manually and send it over ....
encoded = Base64.encode64(string)
attachments['test_file.txt'] = {
mime_type: 'text/plain;charset=utf-8',
encoding: 'base64',
content: encoded
}
And that seems to have done the trick. My attachment now contains carriage return and line feed endings ("\r\n")
I'm not sure if this is expected functionality for the ActionMailer. I definitely didn't expect it.
i'm want to generate CSV data and send it via mail to some email-address. For the generation of the CSV i'm using FasterCSV with the following code:
csv_data = FasterCSV.generate(:col_sep => ";") do |csv|
csv << ["timestamp", "staff_firstname", "staff_lastname", "message"]
log.each do |log_entry|
csv << [log_entry.timestamp, log_entry.staff_firstname, log_entry.staff_lastname, log_entry.message]
end
end
The csv_data i want to send via a ActionMailer method and therefore i'm using the following code:
def log_csv_export(log_csv, email)
mail.attachments["log.csv"] = log_csv
mail(:to => email, :subject => 'Export Log' )
end
To call the ActionMailer method i'm using:
AccountMailer.log_csv_export(csv_data, email).deliver
If I test it, the mail was send to the transmitted email address, but without an attachment. The csv-data is shown as plain text in the email, but not as attachment to save.
This problem only occurs if i send the mail via heroku mailgun. If i'm testing it with
ActionMailer::Base.delivery_method = :sendmail in the config, then it works.
Did someone knows what the issue is or what i need to change that it works?
Thank you.