Rails 3.2 ActionMailer not rendering html in production - ruby-on-rails

I have a production machine that is your basic CentOS machine on Amazon AWS, nothing special there.
I am essentially running this:
#digest = WeeklyDigest.most_recent.first
#mailer = DigestMailer.weekly_digest(#digest)
#mailchimp = MailChimp.new
#mailchimp.new_digest(#mailer.body.to_s)
What this code does is finds my latest weekly_digest, generate a new mailer using that, and then I grab the html from that and send it to mailchimp.
I have a weekly_digest.html.slim in app/views/digest_mailer and I have a digest_mailer.html.slim in app/views/layouts.
All of this works fine on development. #mailer returns this:
#<Mail::Message:70180219750380, Multipart: false, Headers: <From: no-reply#example.com>, <To: fake#fake.com>, <Subject: Weekly Digest>, <Mime-Version: 1.0>, <Content-Type: text/html>>
When I run the exact same code on my AWS machine it returns:
#<Mail::Message:158221880, Multipart: false, Headers: <From: no-reply#example.com>, <To: fake#fake.com>, <Subject: Weekly Digest>, <Mime-Version: 1.0>, <Content-Type: text/plain>>
The content type on dev is html and its text/plain on prod.
Any ideas about why this might happen? Something in the environment settings? I'm not finding much helpful in the docs.

Could be a discrepancy in default_content_type between your environment configurations. Try adding:
config.action_mailer.default_content_type = 'text/html'
To either your production.rb config file, or optionally your application.rb config file.
You should also check if a text template exists at app/views/digest_mailer/weekly_digest.text.erb and remove it since you're only trying to send HTML emails anyway.
Longterm you should consider sending multipart emails with both text and HTML. The Premailer Gem makes it really easy by automatically generating the text-part from the HTML template. That way you don't have to maintain both a text and HTML template and keep them in sync.

Related

Shrine - Derivation Endpoint and full path URLs with Cloudfront

I'm using Shrine with Rails to upload my images directly to S3, they are then served using Cloudfront.
My setup is working great, but I'm stuck trying to answer 2 issues:
1) User uploads a new Image via Uppy. They click "Create Image Page" which creates a new "page" object. The user is taken to a blank page, while the Image derivative is being created in a background process using Sidekiq. How can we have the image "pop-in" via JS once the derivative is successfully created and promoted to /store? Is there a callback we can pick up on, or is it possible to keep trying to find the derivative via JS until it exists?
2) Using the Derivatives Endpoint plugin, all of the image URLs are relative. Is there a way to serve this as absolute URLs from Cloudfront/Custom Domain? Here's an example using Rails:
Ruby code:
<%= image_tag(image.image_file.derivation_url(:banner, 800, 300)) %>
Resulting HTML:
<img src="/derivations/images/banner/800/300/...">
How can I instead serve this resulting URL:
<img src="http://abc123.cloudfront.net/derivations/images/banner/800/300/...">
Was this intentional to prevent DoS? Thanks.
Adding the host option to "derivation_endpoint" causes the following error returned as XML:
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>...</RequestId>
<HostId>...</HostId>
</Error>
Could this be my Cloudfront access settings? Maybe CORS.
Here is my derivation_endpoint setup in image_uploader.rb
plugin :derivation_endpoint, host: "http://abc123.cloudfront.net", prefix: "derivations", secret_key: ..., upload: true
routes.rb
mount Shrine.presign_endpoint(:cache) => "s3/params"
mount PhotoUploader.derivation_endpoint => "derivations/images"
config/initializers/Shrine.rb
Shrine.plugin :url_options, store: { host: "http://abc123.cloudfront.net" }
Since the background job will update the record with derivatives, the easiest would be to poll the "show" route of the record (i.e. GET /images/:id) on the client side. In this case the route could have an alternative JSON response via respond_to.
Alternatively, you could send a message from the background job to the client once processing is finished, via WebSockets or something like message_bus.
You can configure the :host option for the derivation_endpoint plugin:
Shrine.plugin :derivation_endpoint, host: "https://cloudfront.net"

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.

WickedPdf encoding error in only production

I'm novice in rails. I really get in trouble.
Because log isn't tell me what error is it.
I using Korea (UTF-8).
So I set meta tag
%meta{:content => "text/html; charset=utf-8", "http-equiv" => "content-type"}/
and wickedpdf config
format.pdf do
pdf_config
render pdf: "상담 일지-#{ Time.now.strftime("%m-%d %I%p")}.pdf",
layout: 'layouts/application.pdf.haml',
encoding: 'utf8'
end
However
My pdf view in production env is folloing.
However my pdf view in development and staging env is following
I has been googling 5 hour. But It is really strange error. Anyone alse could help me?.....
Anyway, Thank you for listen my question! I hope you solve my problem.

what does the ActionMailer deliver command return?

I'm trying to figure out how to gracefully inform a user that an e-mail has not been sent from Rails.
The issue is this line of code:
OrderNotifier.received(#order).deliver
and what happens when the smtp server does not respond to the deliver command (smtp server is down, for instance). I've seen example code like:
#response_from_deliver = OrderNotifier.received(#order).deliver
but can find no documentation that says either this is a valid assignment or, if it is, what the various responses from an ActionMailer deliver might be.
Thanks for any information.
You will get back the Mail::Message object type. Apidock.com looks like it has some good information on ActionMailer.
#<Mail::Message:70225058423980,
Multipart: false, Headers: <Date: Mon, 20 Jan 2014 12:06:05 -0600>,
<From: info#socialrest.me>,
<To: myemail#gmail.com>,
<Message-ID: <52dd658d8f0f7_11643fde8d219160235e4#iMac.local.mail>>,
<Subject: Welcome to My Site>,
<Mime-Version: 1.0>,
<Content-Type: text/html>,
<Content-Transfer-Encoding: quoted-printable>>

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.

Resources