postmark-rails gem

Build Status Code Climate

The Postmark Rails Gem is a drop-in plug-in for ActionMailer to send emails via Postmark, an email delivery service for web apps. The gem has been created for fast implementation and fully supports all of Postmark’s features.

Supported Rails Versions

  • Rails 5.0
  • Rails 4.x
  • Rails 3.x

For Rails 2.3 please take a look at version 0.4. It may miss some new features, but receives all required bug fixes and other support if needed.

Configuring your Rails application

Add postmark-rails to your Gemfile and run bundle install.

gem 'postmark-rails'

Save your Postmark API token to config/secrets.yml.

postmark_api_token: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Set Postmark as your preferred mail delivery method via config/application.rb:

config.action_mailer.delivery_method = :postmark
config.action_mailer.postmark_settings = { :api_token => Rails.application.secrets.postmark_api_token }

Note: The postmark_settings hash can contain any options supported by Postmark::ApiClient.

Tracking opens and tagging your deliveries

You can use tags to categorize outgoing messages and attach application-specific information. Tagging the different types of email that you send lets you review statistics and bounce reports separately.

Pass :track_opens => 'true' to enable/disable open tracking on per-message basis. Check out the Triggers API to see how Postmark can help you control this with tags. Note that we pass a string here, since it becomes a header value. Passing a boolean may or may not work depending on your Rails version.

class TestMailer < ActionMailer::Base

  def tagged_message
    mail(
      :subject => 'hello',
      :to      => '[email protected]',
      :from    => '[email protected]',
      :tag     => 'my-tag',
      :track_opens => 'true'
    )
  end

end

Sending attachments

You can also send file attachments with Postmark. Read our Developer docs for additional information.

The Postmark gem is compatible with ActionMailer attachments API. It allows you to specify the name, content-type and other attributes for your attachments.

The legacy :postmark_attachments attribute is no longer supported on Rails 3.2.13 and above.

class TestMailer < ActionMailer::Base

  def message_with_attachment
    attachments.inline['logo.png'] = File.read("/path/to/image") # Inline image
    attachments['42.jpg'] = File.read("/path/to/file") # Attached file
    mail(
      :subject              => 'hello',
      :to                   => '[email protected]',
      :from                 => '[email protected]'
    )
  end

end

Attaching metadata to messages

Postmark supports attaching metadata to messages. All metadata field values will be interpreted and returned in webhook payloads as strings.

class TestMailer < ActionMailer::Base

  def 
    ['foo'] = 'bar'
    mail(
      :subject              => 'meta hello',
      :to                   => '[email protected]',
      :from                 => '[email protected]'
    )
  end

end

Sending in batches

While Postmark is focused on transactional email, we understand that developers with higher volumes or processing time constraints need to send their messages in batches. To facilitate this we provide a batching endpoint that permits you to send up to 500 well-formed Postmark messages in a single API call.

client = Postmark::ApiClient.new('your-api-token')

messages = []
messages << DigestMailer.weekly_digest(@user1)
messages << DigestMailer.weekly_digest(@user2)

client.deliver_messages(messages)

messages.first.delivered?
# => true

messages.all?(&:delivered)
# => true

Error handling

The gem respects the ActionMailer::Base.raise_delivery_errors setting and will surpress any exceptions if it’s set to false. When delivery errors are enabled, the gem can raise any one of the exceptions listed in the postmark gem docs.

ActionMailer 5

For ActionMailer 5 and above, use ActionMailer::Base.rescue_from to define handlers for each error you care about.

Example

class ApplicationMailer < ActionMailer::Base
  default from: '[email protected]'
  layout 'mailer'

  rescue_from Postmark::InactiveRecipientError, with: :reactivate_and_retry

  private

  def postmark_client
    ::Postmark::ApiClient.new(ActionMailer::Base.postmark_settings[:api_token],
                              ActionMailer::Base.postmark_settings.except(:api_token))
  end


  # This is just an example. Sometimes you might not want to reactivate
  # an address that hard bounced.
  # Warning: Having too many bounces can affect your delivery reputation
  # with email providers
  def reactivate_and_retry(error)
    Rails.logger.info("Error when sending #{message} to #{error.recipients.join(', ')}")
    Rails.logger.info(error)

    error.recipients.each do |recipient|
      bounce = postmark_client.bounces(emailFilter: recipient).first
      next unless bounce
      postmark_client.activate_bounce(bounce[:id])
    end

    # Try again immediately
    message.deliver
  end
end

ActionMailer 4 and below

Wrap any calls to #deliver_now in error handlers like the one described in the postmark gem docs.

Rails 4.2 introduces #deliver_later but doesn’t support rescue_from for mailer classes. Instead, use the following monkey patch for ActionMailer::DeliveryJob.

# app/mailers/application_mailer.rb

class ApplicationMailer < ActionMailer::Base
  default from: '[email protected]'
end

class ActionMailer::DeliveryJob
  rescue_from Postmark::InactiveRecipientError, with: :reactivate_and_retry

  def postmark_client
    ::Postmark::ApiClient.new(ActionMailer::Base.postmark_settings[:api_token],
                              ActionMailer::Base.postmark_settings.except(:api_token))
  end


  # This is just an example. Sometimes you might not want to reactivate
  # an address that hard bounced.
  # Warning: Having too many bounces can affect your delivery reputation
  # with email providers
  def reactivate_and_retry(error)
    Rails.logger.info("Error when sending a message to #{error.recipients.join(', ')}")
    Rails.logger.info(error)

    error.recipients.each do |recipient|
      bounce = postmark_client.bounces(emailFilter: recipient).first
      next unless bounce
      postmark_client.activate_bounce(bounce[:id])
    end

    # Try again immediately
    perform(*arguments)
  end
end

Additional information

Looking for the advanced usage examples? Check out the documentation for the postmark gem. The postmark-rails gem is built on top of it, so you can benefit from all its features.

Requirements

  • postmark gem version 1.0 and higher is required.
  • You will also need a Postmark account, a server and at least one sender signature set up to use it. To get an account, sign up!

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so we don’t break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history.
  • Send a pull request. Bonus points for topic branches.

Authors & Contributors

  • Artem Chistyakov
  • Petyo Ivanov
  • Ilya Sabanin
  • Hristo Deshev
  • Randy Schmidt
  • Chris Williams
  • Nicolás Sanguinetti
  • Laust Rud Jacobsen (rud)

Copyright © 2010—2018 Wildbit LLC. See LICENSE for details.