class MultiMail::Receiver::Cloudmailin

Cloudmailin's incoming email receiver.

Cloudmailin recommends using basic authentication over HTTPS to ensure that a request originates from Cloudmailin.

@see docs.cloudmailin.com/receiving_email/securing_your_email_url_target/

Public Class Methods

new(options = {}) click to toggle source

Initializes a Cloudmailin incoming email receiver.

@param [Hash] options required and optional arguments @option options [String] :http_post_format “multipart”, “json” or “raw” @option options [Boolean] :attachment_store whether attachments have

been sent to an attachment store
Calls superclass method MultiMail::Receiver::Base::new
# File lib/multi_mail/cloudmailin/receiver.rb, line 20
def initialize(options = {})
  super
  @http_post_format = options[:http_post_format]
  @attachment_store = options[:attachment_store]
end

Public Instance Methods

spam?(message) click to toggle source

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

# File lib/multi_mail/cloudmailin/receiver.rb, line 106
def spam?(message)
  message.spf_result == 'fail'
end
transform(params) click to toggle source

@param [Hash] params the content of Cloudmailin's webhook @return [Array<MultiMail::Message::Cloudmailin>] messages @see docs.cloudmailin.com/http_post_formats/multipart/ @see docs.cloudmailin.com/http_post_formats/json/ @see docs.cloudmailin.com/http_post_formats/raw/

# File lib/multi_mail/cloudmailin/receiver.rb, line 31
def transform(params)
  case @http_post_format
  when 'raw', '', nil
    message = self.class.condense(MultiMail::Message::Cloudmailin.new(Mail.new(params['message'])))

    # Extra Cloudmailin parameters.
    message.spf_result = params['envelope']['spf']['result']

    if @attachment_store
      params['attachments'].each do |_,attachment|
        message.add_file(:filename => attachment['file_name'], :content => Faraday.get(attachment['url']).body)
      end
    end

    # Discard rest of `envelope`: `from`, `to`, `recipients`,
    # `helo_domain` and `remote_ip`.
    [message]
  when 'multipart', 'json'
    # Mail changes `self`.
    headers = self.class.multimap(params['headers'])
    http_post_format = @http_post_format
    attachment_store = @attachment_store
    this = self

    message = MultiMail::Message::Cloudmailin.new do
      headers headers

      text_part do
        body params['plain']
      end

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

      if params.key?('attachments')
        # Using something like lazy.rb will not prevent the HTTP request,
        # because the Mail gem must be able to call #valid_encoding? on
        # the attachment body (in Ruby 1.9).
        if http_post_format == 'json'
          params['attachments'].each do |attachment|
            if attachment_store
              add_file(:filename => attachment['file_name'], :content => Faraday.get(attachment['url']).body)
            else
              add_file(:filename => attachment['file_name'], :content => Base64.decode64(attachment['content']))
            end
          end
        else
          params['attachments'].each do |_,attachment|
            if attachment_store
              add_file(:filename => attachment['file_name'], :content => Faraday.get(attachment['url']).body)
            else
              add_file(this.class.add_file_arguments(attachment))
            end
          end
        end
      end
    end

    # Extra Cloudmailin parameters. The multipart format uses CRLF whereas
    # the JSON format uses LF. Normalize to LF.
    message.reply_plain = params['reply_plain'].gsub("\r\n", "\n")
    message.spf_result  = params['envelope']['spf']['result']

    [message]
  else
    raise ArgumentError, "Can't handle Cloudmailin #{@http_post_format} HTTP POST format"
  end
end