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
Related
I get Missing template when trying to send an email with a pdf attachment:
Controller
respond_to do |format|
format.html
format.pdf do
render pdf: "job card ##{#bike_service.id} - #{DateTime.now}", :template => 'bike_services/show.html.erb' # Excluding ".pdf" extension.
end
end
BikeServiceMailer.job_card_pdf_email(BikeService.last.id).deliver_now
end
Mailer
def job_card_pdf_email(bike_service_id)
bike_service = BikeService.find(bike_service_id)
attachments["bike_service_#{bike_service.id}-#{DateTime.now}.pdf"] = WickedPdf.new.pdf_from_string(
render_to_string(pdf: 'bike_service', template: File.join('app', 'views', 'bike_services', 'show.pdf.erb'), layout: 'pdf.html')
)
mail(to: todo.owner.email, subject: 'Your job card PDF is attached', bike_service: bike_service)
end
The show.pdf.erb template is there already.
I think you need to change the render_to_string line to either:
render_to_string(pdf: 'bike_service', template: File.join('bike_services', 'show.pdf.erb'), layout: 'pdf.html')
or
render_to_string(pdf: 'bike_service', template: Rails.root.join('app', 'views', 'bike_services', 'show.pdf.erb'), layout: 'pdf.html')
At the moment, I think the system is looking for app/views/bike_services/show.pdf.erb in /Users/vangama/projects/mm-crm/app/views which is effectively /Users/vangama/projects/mm-crm/app/views/app/views/bike_services/show.pdf.erb which doesn't exist.
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
I am trying to development this app that has a landing page where i can collect email addresses, log in as an admin and send mail to all the subscribed users, i am using Action mailer and my gmail account smtp configuration.
When i do send the mail, everyone gets cc'ed, and seeing as i am testing with my own google mail accounts, i can see the other people cc'ed.
Mailforsubcriber Controller
def create
#mailforsubscriber = Mailforsubscriber.new(mailforsubscriber_params)
respond_to do |format|
if #mailforsubscriber.save
RecipientMailer.newsletter(#mailforsubscriber).deliver_now
format.html { redirect_to #mailforsubscriber, notice: 'Mail for subscriber was successfully sent.' }
format.json { render :show, status: :created, location: #mailforsubscriber }
else
format.html { render :new }
format.json { render json: #mailforsubscriber.errors, status: :unprocessable_entity }
end
end
end
This is the recipient mailer code
class RecipientMailer < ApplicationMailer
require 'digest/sha2'
default from: "notification#example.com"
default to: Proc.new {Subscribeduser.pluck(:email) }
default "Message-ID" => "#{Digest::SHA2.hexdigest(Time.now.to_i.to_s)}#domain.com"
def newsletter(mailforsubscriber)
#mailforsubscriber = mailforsubscriber
mail(subject: "Newsletter")
end
end
how do i get around this?.
try use the CCO field, it's works like CC field, but don't show the other e-mails for everyone.
You can use something like this in your action mailer,
def newsletter(mailforsubscriber)
#mailforsubscriber = mailforsubscriber
mail(:to => #mailforsubscriber.email, :subject => "Newsletter")
end
Here i have called the method send_mail_persons and passed the recipients info as a parameter.This logic will make you loop across all the email ids and then send individually. If you want to send mail to all the users at once then you can use :bcc, say
mail(:to => "#mailforsubscriber.email" , :subject => "Example Subject",
:bcc => ["bcc1#abc.com", "bcc2#abc.com"])
If you are new to Rails, i would suggest to read this Action Mailer Basics. This covers end to end flow of a basic mailer template integration from controller to view.
Controller method
def email_pdf
#job = Job.find_by_id(params[:id].to_i)
job_pdf = WickedPdf.new.pdf_from_string(render_to_string(:pdf => 'job', :template => 'job/show.pdf.erb', layout: 'mailer.html.erb'))
JobMailer.send_jobs_email(params[:id].to_i, 'vir.jain#gmail.com', 'Mahavir Jain', job_pdf).deliver_now
respond_to do |format|
format.json do
render :json => {:success => true}, :status => 200
end
end
end
Job Mailer
class JobMailer < ApplicationMailer
def send_jobs_email(job_id, email, name, job_pdf)
#name = name
#job = Job.find_by_id(job_id)
puts 'hello1'
attachments['job'] = job_pdf
puts #name
mail(to: email, subject: 'Job', from: 'info#janatrak.com', from_name: 'JanaTrak Admin')
end
end
Output
Rendered job/show.pdf.erb within layouts/mailer.html.erb (15.0ms)
"***************[\"/usr/local/bin/wkhtmltopdf\", \"-q\", \"file:///var/folders/dk/t3scf65x5vx23qq1fsm53s3r0000gn/T/wicked_pdf20151007-4801-h2de03.html\", \"/var/folders/dk/t3scf65x5vx23qq1fsm53s3r0000gn/T/wicked_pdf_generated_file20151007-4801-7uwh23.pdf\"]***************"
"***************[\"/usr/local/bin/wkhtmltopdf\", \"-q\", \"file:///var/folders/dk/t3scf65x5vx23qq1fsm53s3r0000gn/T/wicked_pdf20151007-4801-mp6b6i.html\", \"/var/folders/dk/t3scf65x5vx23qq1fsm53s3r0000gn/T/wicked_pdf_generated_file20151007-4801-3bayit.pdf\"]***************"
Rendered job_mailer/send_jobs_email.html.erb within layouts/mailer (0.1ms)
[{"email"=>"vir.jain#gmail.com", "status"=>"sent", "_id"=>"dc93087c39a949de827df06a1edb116e", "reject_reason"=>nil}]
Problem
From output, I can see, I am able to generate pdf properly but for some reason, it's not sending pdf as attachment. Also it's not sending email content. But when I remove attachment from code, it do properly send content of email.
I did checked
Rails 3 ActionMailer and Wicked_PDF
and tried both solution but none worked.
I'm using rails 4.2, ruby 2.1.2, wkhtmltopdf 0.12.2.1 (with patched qt).
Any help is really appreciated
***************** UPDATE ************************
Controller Method
def email_pdf
#job = Job.find_by_id(params[:id].to_i)
self.instance_variable_set(:#lookup_context, nil)
self.instance_variable_set(:#_lookup_context, nil)
job_pdf = WickedPdf.new.pdf_from_string(render_to_string(:template => 'job/show.pdf.erb', layout: 'mailer.html.erb'))
#job_pdf = WickedPdf.new.pdf_from_string('<h1>Hello There!</h1>')
save_path = Rails.root.join('pdfs','job.pdf')
dir = File.dirname(save_path)
FileUtils.mkdir_p(dir) unless File.directory?(dir)
File.open(save_path, 'wb') do |file|
file << job_pdf
end
JobMailer.send_jobs_email(params[:id].to_i, 'vir.jain#gmail.com', 'Mahavir Jain', save_path).deliver_now
respond_to do |format|
format.json do
render :json => {:success => true}, :status => 200
end
end
end
Mailer Method
def send_jobs_email(job_id, email, name, job_pdf)
#name = name
#job = Job.find_by_id(job_id)
puts 'hello1'
attachments['job.pdf'] = File.read(job_pdf)
puts job_pdf
mail(to: email, subject: 'Job', from: 'info#janatrak.com', from_name: 'JanaTrak Admin')
end
PDF is generating properly & i can see saved pdf.. But again somehow actionmailer not attaching pdf as well as not displaying content..
Am I anything missing related to actionmailer attachment?
I'm trying to put some logic into my mailer. Basically, I have a dozen boolean fields in one of my models and for each field that is true, I want an email to be sent to a specific address. The model with the boolean fields is called Ecn. This is my notifier file:
class EcnNotifier < ActionMailer::Base
default from: "engineering_notices#wilfley.com"
def submitted(ecn)
#ecn = ecn
#email_list = EmailList.all
if #ecn.distribute_engineering?
mail to: "abc#gmail.com", subject: 'ECN approvald'
else
end
if #ecn.distribute_purchasing?
mail to: "123#gmail.com", subject: 'ECN approval'
else
end
mail to: "aaa#test.com", subject: 'ECN approval'
end
end
And the action I've created in my controller looks like this:
def submit
#ecn = Ecn.find(params[:id])
respond_to do |format|
EcnNotifier.submitted(#ecn).deliver
format.html { redirect_to ecns_url, alert: "Ecn has been submitted for approval." }
format.json { render json: #ecns }
end
end
An email gets sent automatically to aaa#test.com, but regardless of whether or not the distribute_engineering and distribute_purchasing are true, an email is not sent to the other addresses. I'm assuming I'm incorrectly accessing my object instance, but I'm not sure where I'm going wrong.
I thought that you only can send one mail in one mailer action, and not multiple mails. You can send one mail and add a few cc or bcc, but only can send one mail within the scope of one action.
I would change the controller to following:
def submit
#ecn = Ecn.find(params[:id])
respond_to do |format|
EcnNotifier.notify_default(#ecn).deliver
EcnNotifier.distribute_engineering(#ecn).delifer if #ecn.distribute_engineering?
EcnNotifier.distribute_purchasing(#ecn).deliver if #ecn.distribute_purchasing?
# and so on...
format.html { redirect_to ecns_url, alert: "Ecn has been submitted for approval." }
format.json { render json: #ecns }
end
end
And your EcnNotifier mailer:
class EcnNotifier < ActionMailer::Base
default from: "engineering_notices#wilfley.com"
def notify_default(ecn)
#ecn = ecn
#email_list = EmailList.all
mail to: "aaa#test.com", subject: 'ECN approval'
end
def distribute_engineering(ecn)
#ecn = ecn
#email_list = EmailList.all
mail to: "abc#gmail.com", subject: 'ECN approval'
end
def distribute_purchasing(ecn)
#ecn = ecn
#email_list = EmailList.all
mail to: "abc#gmail.com", subject: 'ECN approval'
end
end
Btw: if you are sending multiple mails, you should do that via delayed job gem or something like that. Otherwise the user has to wait quite a long time, because the ruby process will be blocked during sending all the mails. the delayed job gem is available on github: https://github.com/collectiveidea/delayed_job
You can only send one mail with one call of deliver. You have to move your logic outside the mailer or use cc or bcc to deliver the mail to multiple recipients.