I'm trying to send mail in ROR using ActionMailer class.
I have created a mail object like :
mail(to: 'xyz#gmail.com', subject: "some subject text", body: template)
Here template is a string which contains the HTML to be rendered in the mail body.
When I'm trying the above declaration, the HTML string is getting displayed as it is in Gmail or any other client rather then getting rendered.
I'm aware of the fact that I can make a separate ERB file for view and
mailer views are located in the app/views/name_of_mailer_class
directory.
But I want to the render the HTML string I'm generating from another source inline without storing it in a file.
I have also tried this method I found in the link below, but it is producing the same result. http://carols10cents.github.io/versioned_rails_guides/v3.2.2/action_mailer_basics.html
mail(:to => user.email,
:subject => "Welcome to My Awesome Site") do |format|
format.html { render 'another_template' }
format.text { render :text => 'Render text' }
end
Finally found a way to render HTML without any views file. Making the HTML string html_safe rendered the HTML in email clients.
mail(to: 'xyz#gmail.com', subject: 'some subject text') do |format| format.html { render html: template.to_s.html_safe }
You could do something like this:
#template = template.html_safe
mail(to: 'xyz#gmail.com', subject: "some subject text")
And in your ActionMailer View app/views/name_of_mailer_class just render your string as
<%= #template %>
Hope it helps
Related
Rails will helpfully send multipart email if there are multiple template types present (e.g. .txt and .html files for the same mailer action).
However, what if I want to do this without templates? Normally we specify body and content_type as arguments:
mail to: 'a#example.com', subject: 'Hello', body: 'Hi', content_type: 'text/html'
So how can this be achieved with multiple bodies having their own type?
class TestMailer < ActionMailer::Base
def welcome_email
mail(to: 'example#example.com', subject: 'Welcome to My Awesome Site') do |format|
format.html { render html: '<h1>Welcome XYZ!</h1>'.html_safe }
format.text { render plain: 'Welcome XYZ' }
end
end
end
To use it call: TestMailer.welcome_email.deliver_now.
Documentation, section 2.4
I'm using wick_pdf in my Rails 4 app to convert several html templates into pdfs. I then attach these pdfs to an outbound email. The email and the pdfs are sending correctly, but there is an additional blank pdf (occasionally not completely) that gets sent along with my desired pdfs. I've attached my code below. Please let me know if you have any suggestions.
def approval_notification(id)
#user = User.find(id)
esign = WickedPdf.new.pdf_from_string(render_to_string pdf: "esign", template: "disclosures/pdfs/esign_pdf.html.erb", formats: :html, encoding: "UTF-8")
mail(:to => #user.email, :subject => 'Congratulations! You have been approved!') do |format|
format.html
format.pdf do
attachments['Electronic_Signature.pdf'] = esign
end
end
end
Update:
Alright, I managed to fix the issue. I still don't completely understand what was wrong so please explain if you know. The revised code is below:
def approval_notification(id)
#user = User.find(id)
esign = WickedPdf.new.pdf_from_string(render_to_string pdf: "esign", template: "disclosures/pdfs/esign_pdf.html.erb", formats: :html, encoding: "UTF-8")
attachments['Electronic_Signature.pdf'] = esign
mail(:to => #user.email, :subject => 'Congratulations! You have been approved!')
end
I'm trying so send an email like this
mail(:to => #user.email, :from => from_email, :subject => t('orders.invoice.email_subject'), :content_type => "text/html") do |format|
format.html { render partial: "notifier/follow_up_email.#{I18n.locale}.html.erb", locals: {storefront: storefront, order: order} }
end
Unfortunately, rails is only looking for follow_up_email.en.html and not follow_up_email.en.html.erb - What am I doing wrong?
render partial: ... should not contain file extensions such as en.html.erb since they are automagically added.
http://api.rubyonrails.org/classes/ActionView/PartialRenderer.html
But why do you use partials for mails, couldn't you create a proper view?
UPDATE
It's all described in the guide on http://guides.rubyonrails.org/v3.2.16/action_mailer_basics.html
app/mailers/user_mailer.rb:
class UserMailer < ActionMailer::Base
default from: "no-reply#memyselfandi.com"
def notification(user, storefront, order)
#user, #storefront, #order = user, storefront, order
I18n.locale = #user.locale # see note below
mail to: #user.email, subject: I18n.t('orders.invoice.email_subject')
end
end
app/views/user_mailer/notification.en.html.erb:
<html><body>
This is a mail for <%= #user.email %> yadda yadda. Use #storefront and #order here.
</body></html>
app/views/user_mailer/notification.de.html.erb:
<html><body>
Das ist ein mail für <%= #user.email %> bla bla.
</body></html>
The line I18n.locale = #user.locale is only necessary if you want to send async mails e.g. when triggering rake tasks from a cronjob.
Our Rails (3.0.14) application has user profiles where users can choose whether they want to receive HTML formatted emails. To keep things DRY, I would like to only setup one set of templates for all mails (HTML) and then use my own String extension dehtml (basically strip_tags with some formatting modifications) on the text/plain part. Also, I would like to keep the mailer code DRY.
So far, our mailer methods look like this:
def signup_confirmation(user)
#user = user
mail(:to => #user.email, :subject => ..., ...)
end
1. DRY templates: If possible, I would like to avoid having to create 200 additional mail templates, and autocreate the text/plain part from the HTML template. This is the basic idea (dehtml is my own String extension):
def signup_confirmation(user)
#user = user
mail(:to => #user.email, :subject => ..., ...) do |format|
format.html
format.text { render(:file => 'signup_notification.html').dehtml }
end
end
However, this fails with a 'missing template' error. How do I tell Rails to use the HTML template in both cases? I tried appending :formats => :html and :handler => :html but this didn't help.
I don't have a solution here right now. Any ideas?
2: DRY mailer methods:
Since our users should be able to decide whether they want to have HTML or not, the above method will look something like
def signup_confirmation(user)
#user = user
attachments.inline["email-header.jpg"] = File.read(...) if #user.wants_html
mail(:to => #user.email, :subject => ..., ...) do |format|
format.html if #user.wants_html
format.text { render(:file => 'signup_notification.html').dehtml }
end
end
Altogether, this triples the LOC in each method. I would like to DRY this up (since it will have to be inserted into at least 200 mailer methods) as far as possible. One idea would be to write my own mail method (let's call it mymail) as something like
def mymail(user, p={})
attachments.inline["email-header.jpg"] = File.read(...) if user.wants_html
mail(p) do |format|
format.html if user.wants_html
format.text
end
end
(ignoring the above text template problem for now) and then change each call to mail to mymail, as in
def signup_confirmation(user)
#user = user
attachments.inline["email-header.jpg"] = File.read(...) if #user.wants_html
mymail(user, { :to => #user.email, :subject => ..., ... })
end
This works. But is it good practice? Where do I best put mymail - in a helper?
Any insights and recommendations welcome!
I did something very similar to your first solution a long time ago. I don't really remember why it hat to be the way it is, but this is working for me:
def my_mail
mail(:to => #user.email ...) do |format|
format.text { convert_html_to_plain(__method__) } # first text
format.html # then html
end
end
def convert_html_to_plain(method)
old_formats = self.formats
self.formats = ["html"]
rendered = render "#{method}", :layout => false
self.formats = old_formats
# strip tags, reformat, etc. from rendered
rendered << render(:partial => "plaintext_footer", :locals => {:user => #user}, :formats => [:text] )
end
I have been using Wicked_pdf to render a view as a PDF and actionmailer to send emails, but I can't get them to work together. I want to attach a PDF version of a certain view to an email using actionmailer and send it out by clicking a link or a button. I have a link_to command that sends out an email. Here is my controller that gets the email generated:
def sendemail
#user = User.find(params[:id])
Sendpdf.send_report(#user).deliver
redirect_to user_path(#user)
flash[:notice] = 'Email has been sent!'
end
Here is what I have in my actionmailer:
class Sendpdf < ActionMailer::Base
default :from => "myemail#email.com"
def send_report(user)
#user = user
attachment "application/pdf" do |a|
a.body = #Something should go here, maybe WickedPDF.new.something?
a.filename = 'MyPDF'
end
mail(:to => user.email, :subject => "awesome pdf, check it")
end
end
I have seen many questions and answers, most dealing with Prawn. It seems like there should be a simple answer to this. Can anyone help?
UPDATE I'm grateful for a suggestion to use as an alternative option in the answer below. However, I would really like to learn how to render a view as a PDF and attach it to my email. I am open to using something different like Prawn or anything else if I need to.
2 good ways to do this the way you want:
1: Create the pdf in the controller, then send that to the email as a param.
# controller
def sendemail
#user = User.find(params[:id])
pdf = render_to_string :pdf => 'MyPDF'
Sendpdf.send_report(#user, pdf).deliver
redirect_to user_path(#user)
flash[:notice] = 'Email has been sent!'
end
# mailer
def send_report(user, pdf)
#user = user
attachments['MyPDF.pdf'] = pdf
mail(:to => user.email, :subject => "awesome pdf, check it")
end
2: Create the pdf in the mailer directly (a little more involved, but can be called from a model)
def send_report(user)
#user = user
mail(:to => user.email, :subject => "awesome pdf, check it") do |format|
format.text # renders send_report.text.erb for body of email
format.pdf do
attachments['MyPDF.pdf'] = WickedPdf.new.pdf_from_string(
render_to_string(:pdf => 'MyPDF',:template => 'reports/show.pdf.erb')
)
end
end
end
There are 2 ways for it.
Either, you want the pdf to be embedded in the email you are sending, so that when the user downloads the pdf from the email, there is no request to the render new pdf action for your respective controller.
I don't know how to do this efficiently because I have never done this before.
Or, you just provide a link to the pdf in your email and when the user clicks on it, now the action for creating the pdf is called, and then the user can download it.
This way, if there is a lot of burden on the server for the downloading of the pdf's, you can redirect these requests somewhere else. In short, there is a huge scope for efficiency.
A sample code for the 2nd method(code provided was written by using PDFkit, so change accordingly):
class PdfsController < ApplicationController
def pdf
respond_to do |format|
format.pdf { render :text => wickedPDF.new( Pdf.find(params[:id]).content ).to_pdf }
end
end
...
end
Replace the Pdf.find(params[:id]).content as per your choice, and the to_pdf method, as per wickedPDF.
Then, you can simply pass the link for the pdf download in your email like this
<%= link_to "Download", pdf_pdf_path(pdf, :format => "pdf") %>
or whatever suits as per wickedPDF.