I'm looking at this tutorial http://guides.rubyonrails.org/action_mailer_basics.html and I get why it would send the html page that is in the view. However how do I send a page that already exists before I created the mailer? I don't want to copy the html and the ruby code over because I don't want another copy of that code to have to maintain.
The page I want to email is an announcements page and there is already another view for the announcements page since it is accessible from other parts of the site.
You can pass :template_path and :template_name hash keys to the specific method in your mailer as in:
mail(:to => user.email,
:subject => "Subject",
:template_path => 'announcements',
:template_name => 'index')
In this case it will look for templates at app/views/announcements with name index.
Related
So recently I was helped out finding a way of using detect in rails to grab a url from text... however that would come very useful for me also in a controller if its possible.
My controller grabs some info and created a new entry into the DB based on incoming params, looks something like this;
#received_msg = Message.create(:content => params[:Text], :user_id => user.id, :status => 'new')
Now, I was hoping that using detect in my controller on the create action, I could search the :content for specific text or symbol and allow my users to define few things in content but I would assign that to a different column. I'm sure this isn't clear so let me show by example.
EXAMPLE:
Let's say my user send a message with content like so;
"Hey there, you should check this type of website out and make sure that its good to go"
Now, I'm assigning a USER_ID for the user that submitted this message, but the original owner could be someone else before the user submitted it. So I thought I would allow my user_id to enter #John into their message, meaning the original owner of the message was JOHN.. the new message would look something like this;
"Hey there, you should check this type of website out and make sure that its good to go #John"
Now in my controller when that message is created as a record, I'd like to take JOHN and assign it to the column username for example; I thought something like this would work but its giving me error .detect undefined..
#received_msg = Message.create(:content => params[:Text], :user_id => user.id, :status => 'new', :username => (params[:Text].detect {|original_sender| original_sender.start_with? "#"))
Maybe too many brackets?
you are missing } at the end
#received_msg = Message.create(:content => params[:Text], :user_id => user.id, :status => 'new', :username => (params[:Text].detect {|original_sender| original_sender.start_with? "#"}))
you can also use the below for what you want
#received_msg = Message.create(:content => params[:Text], :user_id => user.id, :status => 'new', :username => params[:Text].split.find{|w| w.start_with?("#")})
def simple_mail(to, subject, body)
attachments.inline['Logo.png'] = File.read( Rails.root.join("public", "Logo.png"))
mail(:to => to, :subject => subject, :body => body)
end
I receive an attachment to the message, but it is not an "inline" image. How can I attach inline, and how can I choose where it goes?
I'm seeing examples that have views for their mailer.. looks like I may need to set those up. If so, how do I link Action Mailer views to a message?
As you see in guides.rubyonrails, you can link a view to your mailer the same way you link a view to a controller's action. if your mailer is called my_mailer, and your mailer action is called simple_mail, then create a view in app/views/my_mailer/ and call it "simple_mail.html.erb". As well, you can create a "simple_mail.text.erb" to make sure that if the recipient can't receive HTML e-mails, they get the plaintext version (see action_mailer_basics.html below).
As for inline attachments, a different question was raised previously regarding views (see this link) and scaney answered with a couple links. Check out this link and search the text for "inline" and you should find the answer you're looking for!
http://guides.rubyonrails.org/action_mailer_basics.html
api.rubyonrails.org/classes/ActionMailer/Base.html
1) To Setup action-mailer views for the mails, you can do it as follows:
Create a view file in app/views/mailer_name/ with the same name as your mailer action (which in this case is "simple_mail" )
Alternatively if you want to use a different view altogether you can also do it as :
def simple_mail(to, subject, body)
attachments.inline['Logo.png']=File.read( Rails.root.join("public", "Logo.png"))
mail(:to => to, :subject => subject, :body => body) do |format|
format.html { render :partial => "/path/to/partial"}
end
end
In the above case, the content of the partial will be rendered as the body of the mail.
2) To attach a inline image you will also need to mention the attachment in the mailer action view file as follows:
<%= image_tag attachments['Logo.png'].url %>
I have everything at the point where I'm about to send out the email but I need to modify all links to include Google Analytics attributes. The problem is that if I try and read/write the html_part.body of the email, the entire html string somehow becomes encoded and doesn't display the email properly (i.e. <html> becomes <html>). I have logged the html_part.body.raw_source in the logger and it shows as proper unencoded HTML, it's only when the email is actually sent does the encoding occur.
EBlast.rb (ActionMailer)
def main(m, args={})
# Parse content attachment references (they don't use helpers like the layout does)
# and modify HTML in other ways
m.prep_for_email self
#email = m # Needed for helper methods in view
mail_args = {
:to => #user.email,
:subject => m.subject,
:template_path => 'e_blast',
:template_name => 'no_template'
}
mail_args[:template_name] = 'main' if m.needs_template?
m.prep_for_sending mail(mail_args)
end
Email.rb
def prep_for_sending(mail_object)
if mail_object.html_part
# If I simply do a 'return mail_object', the email sends just fine...
# but the url trackers aren't applied.
# Replace the content with the entire generated html
self.content = mail_object.html_part.body.decoded
# Add Google analytics tracker info to links in content
apply_url_tracker :source => "Eblast Generator", :medium => :email
# Replace the html_part contents
mail_object.html_part.body = content
# At this point, mail_object.html_part.body contains the entire
# HTML string, unencoded. But when I send the email, it gets its
# entities converted and the email is screwed.
end
# Send off email
mail_object
end
Looks like I'm answering my own question again - I'm on a roll this week.
Apparently setting the body directly creates some odd attribute called 'body_raw' instead of replacing the raw_contents of the html_part. So basically I ended up having a duplicate part embedded in the mail object (I don't know why it does this). Creating a separate Mail::Part and assigning it to html_part just added another part instead of replacing html_part! WTF?!
New Edit: Scratch my last remark about String.replace. It looked like it was working but when I went to another computer and tested it, the same problem of duplication occurred.
Another Edit: Finally?
Before I executed the apply_url_tracker method I had reset the content of the email (for the purposes of changing all the links in the rendered view). I don't have any idea why that screws with the Mail object considering the message should already have been rendered but changing my methodology to the following has fixed the duplication of email parts and their subsequent 'reencoding'. I no longer change the content attribute, I only change the html_part:
def prep_for_sending(message)
if message.html_part
# Replace the html raw_source
message.html_part.body.raw_source.replace apply_url_tracker(message.html_part.body.decoded, :source => "Eblast Generator", :medium => :email)
end
message
end
Clarification:
Even though the call to mail() produces a Mail object with fully rendered HTML/Text parts (i.e., fully rendered views), changing the attribute that is USED by those views (in my case, the 'content' attribute) screws up the final send. Don't modify your model before sending, JUST MODIFY THE MAIL PART DIRECTLY.
The following code seems to work if there is one user, but truncate the email for multiple users:
users.each do |user|
mail(
:to => user.email,
:subject => 'Hi',
:template_name => 'notification'
).deliver
Is this the proper way to send a few emails?
Ruby on Rails 3.2.2
Heroku
SendGrid
I think this is what you're looking for:
def my_mailer_method
users = User.find({ ... })
headers['X-SMTPAPI'] = { :to => users.to_a }.to_json
mail(
:to => "this.will#be.ignored.com",
:subject => "Hi",
:template_name => "notification"
).deliver
end
This sends a message to any number of recipients use the SendGrid's SMTP API. You can find further information on the docs page.
You might also want to take a look at the sendgrid rails gem
To send email to multiple users: pass an array
Replace
:to => user.email
with
:to => users.map(&:email)
more > rails guide
If it is not important for you to hide email addresses from each other, you can specify recipients in a comma delimited string.
It seems that the problem is that each instance of the Mailer can only send one email. Perhaps the mail object is falling out of scope and getting cleaned up by the garbage collector...
The solution that worked was to iterate over the users outside of the Mailer, and call it once for each user. It may be slow but it should happen in the background anyway so it's fine.
Anyone know why rails, places attachments at the top of the email and not the bottom?
Mac Mail, and the Iphone for example show the attachments at the top of the email and not at the bottom, which is very strange.
My user_mailer.rb looks like this:
def error_email
attachments['message.html'] = {:mime_type => 'text/html', :content => message_text }
mail(:to => #message_from, :subject => 'reason whyxxxx')
end
How can I get the attachment at the bottom of the email msg?
Thanks
I've run into this before. A quick fix is to do this in your mailer method to reverse the order of the email parts.
message = mail(:to => #message_from, :subject => 'reason whyxxxx')
message.parts.reverse!
You can sort the parts whichever way you want like this:
body.set_sort_order(order)
body.sort_parts!
-- where order defaults to ['text/plain', 'text/enriched', 'text/html', 'multipart/alternative'].
However this sorts on content type, as far as I can tell, so if your attachment has the same content type as the text part it won't make any difference.