Rails 4 - Postmark integration - ruby-on-rails

I'm trying to figure out how to send transactional email from my Rails 4 app.
I have found tutorials for the postmark gem, but I'm struggling to close the gaps between what's assumed in the tutorials (where to do the suggested steps!) and what I know.
I have installed both the ruby and the rails gems in my gemfile:
gem 'postmark-rails', '~> 0.13.0'
gem 'postmark'
I have added the postmark config to my config/application.rb:
config.action_mailer.delivery_method = :postmark
config.action_mailer.postmark_settings = { :api_token => ENV['POSTMARKKEY'] }
I want to try to make and use email templates in postmark.
The instructions in the postmark gem docs say I need to:
Create an instance of Postmark::ApiClient to start sending emails.
your_api_token = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
client = Postmark::ApiClient.new(your_api_token)
I don't know how to do this step? Where do I write the second line? I have my api token stored in my config. I don't know how to make an instance of the postmark api client.
Can anyone point me to next steps (or a more detailed tutorial)?

After you have installed the gems, you need to create a Mailer. I presume you have already configured the API keys etc. in the correct manner, so I will concentrate on actually sending out a templated / static email.
Lets create app/mailers/postmark_mailer.rb file with the following contents.
class PostmarkMailer < ActionMailer::Base
default :from => "your#senderapprovedemail.com>"
def invite(current_user)
#user = current_user
mail(
:subject => 'Subject',
:to => #user.email,
:return => '74f3829ad07c5cffb#inbound.postmarkapp.com',
:track_opens => 'true'
)
end
end
We can then template this mailer in the file app/views/postmark_mailer/invite.html.erb Let's use the following markup to get you started.
<p>Simple email</p>
<p>Content goes here</p>
You can write it like any other .html.erb template using tags, HTML and alike.
To actually send this email out you need to place an action in your controller, in the following manner.
PostmarkMailer.invite(current_user)
Alternatively, if you want this email to be sent upon visiting homepage, it would most likely look like this:
app/controllers/home_controller.rb with content
class HomeController < ApplicationController
# GET /
def index
PostmarkMailer.invite(current_user)
end
end
and corresponsing route
config/routes.rb with content
root :to => 'home#index'
I hope this answers your question.

Related

Preview emails in rails with text and html

In our Rails 3.2 app we have the following set up to preview emails:
examples_controller
def registration
mail = EventMailer.registration(registration: EventRegistration.last, cache_email: false)
return render_mail(mail)
end
event_mailer.rb
def registration(options = {})
#registration = options[:registration]
#event = Event.find(#registration.event_id)
#subject = options[:subject] || 'Your Learn Registration'
return_email = mail(to: #registration.email, subject: #subject)
# the email if we got it
return_email
end
We just added a text version of the emails, so now in app/views/event_mailer we have registration.html.erb and registration.text.erb. Before adding the text version of the email users could browse to /webmail/examples/registration and view the html version of the email. After adding the text email, that is broken.
Ideas on how to fix this? I tried setting multipart to false in the examples controller, but that did not work.
Also, here is the render_mail method...
def render_mail(mail)
# send it through the inline style processing
inlined_content = InlineStyle.process(mail.body.to_s,ignore_linked_stylesheets: true)
render(:text => inlined_content, :layout => false)
end
I think it's not easy to debug all this code with just seeing some parts, so I'm going to suggest a different solution.
Some time ago I wrote a gem to preview emails (attachments and multiparts as well) in the browser: https://github.com/markets/maily
Main features:
Visual preview via browser (multiparts and attachments)
Template edition (development)
Email delivery
Flexible authorization system
Easy way to hook sample-data for emails
It's a Rails mountable (by default under /maily) engine, so you just need to install it, configure it and you'll be able to preview your email templates in your browser.
You can try to integrate Maily and you'll get a lot of things done, ping me if you have any doubt or suggestion.

Rails mailer and mailer views in subfolder not working

I have a mailer that I can see in my log is getting sent, but the email body does not contain anything from the mailer view.
It's due to the fact that I've put things in subfolders and i've tried using :template_path in my mail function but to no avail.
app/mailers/marketing/marketing_mailer.rb
class Marketing::MarketingMailer < ActionMailer::Base
require 'mail'
address = Mail::Address.new "test#example.com" # ex: "john#example.com"
address.display_name = "Text" # ex: "John Doe"
# Set the From or Reply-To header to the following:
address.format # returns "John Doe <john#example.com>"
default from: address
# Sends an email when someone fills out the contact form
def contact(name, email, message)
#name = name
#email = email
#message = message
mail(:subject => "Test", :to => 'test#example.com', :reply_to => #email) # <== I've tried using :template_path => 'marketing', 'marketing/marketing_mailer', etc, but none worked.
end
end
/app/views/marketing/marketing_mailer/contact.html.erb
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
</head>
<body>
<p>Name: <%= #name %></p>
<p>Email: <%= #email %></p>
<p>Message: <%= #message %></p>
</body>
</html>
I noticed that devise has mailer views inside /views/devise/mailers/... so I know it's possible, but i'm not sure how.
Have you tried mail with {:template_path => 'marketing/marketing_mailer, :template_name =>'contact'} ?
The template name probably expects the namespace in the filename somehow
Does it work without the template Rendering
class Marketing::MarketingMailer < ActionMailer::Base
def welcome_email(user, email_body)
mail(to: user.email,
body: email_body,
content_type: "text/html",
subject: "Already rendered!")
end
end
I came back to this project today and it seems to be finding the template today no problem without having to specify the template_path.
As sad as this is, apparently all I needed to do was stop and restart my server for my mailer views to get picked up. Since other views get picked up without stopping and starting my server, i'm very surprised by this.
Since your file is in the format of .html.erb, you may have to specify that you want to use this format. Like so:
mail(:subject => "Test", :to => 'test#example.com', :reply_to => #email) do
format.html
end
Usually, your template should just be picked up automatically, since the names match up, but there's probably a second file by the same name ending in .text.erb or some other thing that gets in the way of template look-up.
EDIT1 (wild guess)
Aside from template lookup issues, the only other source of problems I can imagine, would be your instance variables. Maybe #message is supposed to be something else and you're interfering with internals, so renaming it might help. According to the code on apidock, mail is using #variables at certain places. This is far fetched though, I admit.
EDIT2 (explanation of the problem faced here)
The behavior behind the actual problem - not finding a new template until server restart - works like this:
A template gets looked up but at that time, it's not present yet. The server doesn't find it, but remembers the fact that it's not there. Then won't look for it again until the next restart, even though you added it.
So, restarting will fix this.
Have you tried turning it off and on again?

"Postmark::InvalidMessageError: Provide either email TextBody or HtmlBody or both." for a rails 3.2 app

I was reading through the Postmark documentation, saw the rails gem there (github link).
I set it up according to the instructions and I ran into this message when I tried sending an email:
Provide either email TextBody or HtmlBody or both.
I have my email settings in my mailer as such:
mail(
:to => user.email,
:subject => "Thanks for signing up",
:from => "me#domain.com",
"HtmlBody" => "<b>Hello</b>",
"TextBody" => "Hello"
)
Please let me know if you need more information. I'm not sure if this is detailed enough for someone who has seen this error before.
Misnaming Email Views
I ran into this same thing and it was due to a misnaming on my part of the views associated with the email.
Example
_user_first_logs_in.html.erb # Was incorrectly using this.
user_first_logs_in.html.erb # Should be using this.
A good way to test for this locally is by using the mail_view gem by our trusted 37signals boys that allows you to preview email in development. Check it out.
That should expose a lot of basic issues.
JP

Dynamically preset a url for development and production environments

I'm creating a password reset functionality for my site in rails and in my mailer password_reset.text.erb file I'm currently sending
http://localhost:3000/password_resets/<%=#user.password_reset_token%>/edit/
in my development environment. This will hit my controller for password reset and redirect the user to edit the password if the token matches with the saved model.
However, I'd like to configure this dynamically so when I deploy to heroku it will know to change that to mywebsite.com/password_resets/...
How would I do this?
EDIT:
def password_reset(user)
#user = user
mail(to: user.email, subject: "Bitelist Password Reset")
end
Typically I configure the host information for the mailer in an appropriate config/environment file.
config.action_mailer.default_url_options = { :host => "example.com" }
You can take a look at the "Generating URLs" section of this page: http://rails.rubyonrails.org/classes/ActionMailer/Base.html
With that configuration set typical routing structures seem to work quite nicely. I am not 100% positive what routes will be available in your situation so you may still need to construct the full URL somewhat manually to include the reset token component.
To generate the actual URLs you can potentially use named routes if your routes are set up in a way that you have a named route that takes a user token. i.e.
<%= edit_password_resets_url(#user.password_reset_token) %>
If you do not have the token integrated into an existing route you may need to manually build the URL:
<%= "#{url_for(:controller => 'password_resets', :action => 'whatever_action_this_is')}/#{#user.password_reset_token}/edit/" %>
or even build it completely manually using default_url_options[:host] and then add the rest that you have above.
If need be you could also set the host at request time although that may be overkill (and will not be thread safe).
def set_mailer_host
ActionMailer::Base.default_url_options[:host] = request.host_with_port
end

Problem with url_for and named routes in ActionMailer View: "Need controller and action"

I'm attempting to provide a confirmation link in my user welcome email and I'm getting the following Rails error:
Need controller and action!
It makes a fuss about this line:
<p>Please take a moment to activate your account by going to:
<%= link_to confirm_user_url(:id => #user.confirmation_code) %>.</p>
In my development.rb environment, I have the following line:
config.action_mailer.default_url_options = {
:host => "localhost", :port => 3000
}
There's no problem with the #user variable. I've tested the email with things like #user.username and #user.confirmation_code. I'm only getting trouble with url_for and named routes like confirm_user_url.
When I check my routes with rake routes, confirm_user shows up, so it's not an issue with the named route not existing.
I can't seem to figure it out. What gives?
ActionMailer isn't a real Rails controller, so routes aren't available in your mailer templates. You need to set up instance variables in your mailer class to pass values to the template.
eg. if your mailer is SampleMailer:
class SampleMailer < ActionMailer::Base
def confirmation_mail(user)
subject 'Confirmation'
recipients user.email
from 'sample#example.com'
sent_on Time.now
body :greeting => 'Sample Greeting', :email => user.email,
:confirm_user_url => confirm_user_url(:id=>#user.confirmation_code)
end
end
Then in the template:
<%= link_to "Confirmation link", #confirm_user_url %>
This is explained somewhat cryptically in the api in the "ActionMailer" section, and in more detail in Agile Web Development with Rails, 3rd Ed., Chapter 25.
Since having a clickable url is what you said in your where after in your comment, here you go macek
<p>Please take a moment to activate your account by going to:
<%= auto_link confirm_user_url(:id => #user.confirmation_code) %>.</p>
I've used the auto_link helper in some of my mailers to make urls clickable and it has worked out pretty well. I think that does email addresses also, check out the full api for all the options. Enjoy.

Resources