rails 3: how to abort delivery method in actionmailer?

A much simpler solution than the accepted answer would be something like:

class SomeMailer < ActionMailer::Base
  def some_method
    if @some_email_data.nil?
      self.message.perform_deliveries = false
    else
      mail(...)  
    end  
  end
end

If you're using Rails 3.2.9 (or later things even better) - there you can finally conditionally call mail(). Here's the related GitHub thread. Now the code can be reworked like this:

class SomeMailer < ActionMailer::Base
  def some_method
    unless @some_email_data.nil?
      mail(...)  
    end  
  end
end

I just encountered same thing here.

My solution was following:

module BulletproofMailer
  class BlackholeMailMessage < Mail::Message
    def self.deliver
      false
    end
  end

  class AbortDeliveryError < StandardError
  end

  class Base < ActionMailer::Base

    def abort_delivery
      raise AbortDeliveryError
    end

    def process(*args)
      begin
        super *args
      rescue AbortDeliveryError
        self.message = BulletproofMailer::BlackholeMailMessage
      end
    end
  end
end

Using these wrapper mailer would look like this:

class EventMailer < BulletproofMailer::Base
  include Resque::Mailer
  def event_created(event_id)
    begin
      @event = CalendarEvent.find(event_id)
    rescue ActiveRecord::RecordNotFound
      abort_delivery
    end
  end
end

It is also posted in my blog.


I've found this method that seems the least-invasive, as it works across all mailer methods without requiring you to remember to catch an error. In our case, we just want a setting to completely disable mailers for certain environments. Tested in Rails 6, although I'm sure it'll work just fine in Rails 5 as well, maybe lower.

class ApplicationMailer < ActionMailer::Base
  class AbortDeliveryError < StandardError; end

  before_action :ensure_notifications_enabled
  rescue_from AbortDeliveryError, with: -> {}

  def ensure_notifications_enabled
    raise AbortDeliveryError.new unless <your_condition>
  end

  ...

end

The empty lambda causes Rails 6 to just return an ActionMailer::Base::NullMail instance, which doesn't get delivered (same as if your mailer method didn't call mail, or returned prematurely).


Setting self.message.perform_deliveries = false did not work for me.

I used a similar approach as some of the other answers - using error handling to control the flow and prevent the mail from being sent.

The example below is aborting mail from being sent in non-Production ENVs to non-whitelisted emails, but the helper method logic can be whatever you need for your scenario.

class BaseMailer < ActionMailer::Base
  class AbortedMailer < StandardError; end

  def mail(**args)
    whitelist_mail_delivery(args[:to])
    super(args)
  rescue AbortedMailer
    Rails.logger.info "Mail aborted! We do not send emails to external email accounts outside of Production ENV"
  end

  private

  def whitelist_mail_delivery(to_email)
    return if Rails.env.production?

    raise AbortedMailer.new unless internal_email?(to_email)
  end

  def internal_email?(to_email)
    to_email.include?('@widgetbusiness.com')
  end
end