class MultiMail::Receiver::Mandrill

Mandrill's incoming email receiver.

Mandrill uses an HTTP header to ensure a request originates from Mandrill.

@see help.mandrill.com/entries/23704122-Authenticating-webhook-requests

Public Class Methods

new(options = {}) click to toggle source

Initializes a Mandrill incoming email receiver.

@param [Hash] options required and optional arguments @option option [Float] :spamassassin_threshold the SpamAssassin score

needed to flag a message as spam
Calls superclass method MultiMail::Receiver::Base::new
# File lib/multi_mail/mandrill/receiver.rb, line 18
def initialize(options = {})
  super
  @spamassassin_threshold = options[:spamassassin_threshold] || 5
  @mandrill_webhook_key = options[:mandrill_webhook_key]
  @mandrill_webhook_url = options[:mandrill_webhook_url]
end

Public Instance Methods

spam?(message) click to toggle source

Returns whether a message is spam.

@param [Mail::Message] message a message @return [Boolean] whether the message is spam

# File lib/multi_mail/mandrill/receiver.rb, line 116
def spam?(message)
  message.spam_report_score > @spamassassin_threshold
end
transform(params) click to toggle source

Transforms the content of Mandrill's webhook into a list of messages.

@param [Hash] params the content of Mandrill's webhook @return [Array<MultiMail::Message::Mandrill>] messages @see help.mandrill.com/entries/22092308-What-is-the-format-of-inbound-email-webhooks-

# File lib/multi_mail/mandrill/receiver.rb, line 44
def transform(params)
  # JSON is necessarily UTF-8.
  JSON.load(params['mandrill_events']).select do |event|
    event.fetch('event') == 'inbound'
  end.map do |event|
    msg = event['msg']

    # Mail changes `self`.
    headers = self.class.multimap(msg['headers'])
    this = self

    message = Message::Mandrill.new do
      headers headers

      # The following are redundant with `message-headers`:
      #
      # address = Mail::Address.new(msg['from_email'])
      # address.display_name = msg['from_name']
      #
      # from    address.format
      # to      msg['to'].flatten.compact
      # subject msg['subject']

      text_part do
        body msg['text']
      end

      # If an email contains multiple HTML parts, Mandrill will only
      # include the first HTML part in its `html` parameter. We therefore
      # parse its `raw_msg` parameter to set the HTML part correctly.
      html = this.class.condense(Message::Mandrill.new(Mail.new(msg['raw_msg']))).parts.find do |part|
        part.content_type == 'text/html; charset=UTF-8'
      end

      if html
        html_part do
          content_type 'text/html; charset=UTF-8'
          body html.body.decoded
        end
      elsif msg.key?('html')
        html_part do
          content_type 'text/html; charset=UTF-8'
          body msg['html']
        end
      end

      if msg.key?('attachments')
        msg['attachments'].each do |_,attachment|
          add_file(:filename => attachment['name'], :content => attachment['content'])
        end
      end
    end

    # Extra Mandrill parameters. Discard `sender` and `tags`, which are
    # null according to the docs, `matched_rules` within `spam_report`,
    # and `detail` within `spf`, which is just a human-readable version of
    # `result`.
    message.ts                = event['ts']
    message.email             = msg['email']
    message.dkim_signed       = msg['dkim']['signed']
    message.dkim_valid        = msg['dkim']['valid']
    message.spam_report_score = msg['spam_report']['score']
    message.spf_result        = msg['spf']['result']

    message
  end
end
valid?(params) click to toggle source

Returns whether a request originates from Mandrill.

@param [Hash] params the content of Mandrill's webhook @return [Boolean] whether the request originates from Mailgun @raise [IndexError] if the request is missing parameters @see help.mandrill.com/entries/23704122-Authenticating-webhook-requests

Calls superclass method MultiMail::Receiver::Base#valid?
# File lib/multi_mail/mandrill/receiver.rb, line 31
def valid?(params)
  if @mandrill_webhook_url && @mandrill_webhook_key
    params.fetch('env').fetch('HTTP_X_MANDRILL_SIGNATURE') == signature(params)
  else
    super
  end
end

Private Instance Methods

signature(params) click to toggle source
# File lib/multi_mail/mandrill/receiver.rb, line 122
def signature(params)
  data = @mandrill_webhook_url
  params.sort.each do |key,value|
    unless key == 'env'
      data += "#{key}#{value}"
    end
  end
  Base64.encode64(OpenSSL::HMAC.digest('sha1', @mandrill_webhook_key, data)).strip
end