kshnurov / mandrill_dm

A basic Mandrill delivery method for Rails.
MIT License
46 stars 45 forks source link

Store mandrill response to Mail::Message #1

Closed mataki closed 9 years ago

mataki commented 10 years ago

I use this gem to access mandrill API.

I want to use mandrill API's response to store mail message id to db.

I think my English is poor to understand. Please read code! :grin:

jlberglund commented 10 years ago

Hi @mataki, I'll take a look at it. Thanks!

PikachuEXE commented 10 years ago

I am using

ActionMailer::Base.add_delivery_method(:mandrill,
  MandrillDm::DeliveryMethod, {
    return_response: true,
})

for now

creativereason commented 10 years ago

@PikachuEXE where are you adding that too? In your configuration or in your mailer class?

@jlberglund any thoughts on moving that pull request into the main gem?

jlberglund commented 10 years ago

Definitely. Should be able to take a look at it this week.

On Sep 22, 2014, at 12:56 PM, Brian Schwartz notifications@github.com wrote:

@PikachuEXE where are you adding that too? In your configuration or in your mailer class?

@jlberglund any thoughts on moving that pull request into the main gem?

— Reply to this email directly or view it on GitHub.

PikachuEXE commented 10 years ago

@creativereason I add that in an initailzer. Adding it in config does not work.

jlberglund commented 10 years ago

@creativereason , did the code snippet from @PikachuEXE work for you? I'd prefer to use the built-in options hash over extending the message class.

PikachuEXE commented 10 years ago

Not sure if the returned response can be wrapped as a custom class I got following code for the response I received after sending:

unless response.is_a?(Mail::Message)
          Vendor::Mandrill::Messages::Send::ProcessResponse.perform({
            response: response,
          })

and the following model for the response:

# @see https://mandrillapp.com/api/docs/messages.ruby.html#method=send
require 'active_support/hash_with_indifferent_access'

module Vendor
  module Mandrill
    module Messages
      module Send
        # JSON parsed response
        class Response

          def initialize(raw_response)
            raise TypeError, "raw_response is a #{raw_response.class}: #{raw_response.inspect}" unless raw_response.is_a?(Array)

            @results = raw_response.map do |raw_result|
              Result.new(raw_result)
            end
          end

          attr_reader :results

          delegate :each, to: :results
        end

        # Note that the response is an array, but result is an object
        class Result

          include ActiveModel::Model

          module Errors
            BaseError        = Class.new(StandardError)
            InvalidStructure = Class.new(BaseError)
            InvalidModel     = Class.new(BaseError)
          end

          module Status
            SEND      = 'sent'.freeze

            QUEUED    = 'queued'.freeze
            SCHEDULED = 'scheduled'.freeze

            REJECTED  = 'rejected'.freeze
            INVALID   = 'invalid'.freeze

            def self.all
              @all ||= constants(false).map do |constant_symbol|
                const_get(constant_symbol)
              end.freeze
            end
          end
          module RejectReason
            HARD_BOUNCE     = 'hard-bounce'.freeze
            SOFT_BOUNCE     = 'soft-bounce'.freeze

            SPAM            = 'spam'.freeze
            UNSUB           = 'unsub'.freeze

            CUSTOM          = 'custom'.freeze

            INVALID_SENDER  = 'invalid-sender'.freeze
            INVALID         = 'invalid'.freeze

            TEST_MODE_LIMIT = 'test-mode-limit'.freeze
            RULE            = 'rule'.freeze

            def self.all
              @all ||= constants(false).map do |constant_symbol|
                const_get(constant_symbol)
              end.freeze
            end
          end

          attr_reader :email, :status, :reject_reason, :message_id

          validates_presence_of :email, :status, :message_id
          validates_inclusion_of :status, in: Status.all
          validates_inclusion_of :reject_reason, in: RejectReason.all,
            allow_blank: true

          def initialize(raw_result_hash)
            raise TypeError, "raw_result_hash is a #{raw_result_hash.class}: #{raw_result_hash.inspect}" unless raw_result_hash.is_a?(Hash)

            initialize_with_result_hash!(raw_result_hash)
          end

          private

          def initialize_with_result_hash!(raw_result_hash)
            h = raw_result_hash.with_indifferent_access

            @email          = h.fetch(:email)
            @status         = h.fetch(:status)
            @reject_reason  = h.fetch(:reject_reason)
            @message_id     = h.fetch(:_id)

            unless valid?
              raise Errors::InvalidModel, errors.messages.inspect
            end

          rescue KeyError => ex
            raise Errors::InvalidStructure, ex.message
          end
        end
      end
    end
  end
end
PikachuEXE commented 10 years ago

Note: The above response only handles normal response, not error response

spovich commented 9 years ago

FYI @jlberglund @PikachuEXE @mataki In the MYOB fork, I implemented this feature IMHO a simpler manner by putting the result on the email delivery_method rather than on the email. https://github.com/MYOB-Technology/mandrill_dm/commit/a25a76b2c8a76632cd99aa564517916aafbc6a90

@jlberglund happy to see you picking things up again! Let me know if you are interested in a PR.

jlberglund commented 9 years ago

@spovich thanks! Will check it out.

jlberglund commented 9 years ago

@spovich that looks like what we need. would be interested in a PR. thanks!

@mataki i'm closing this out in favor of the above approach.

mataki commented 9 years ago

:+1: Thanks.

I think good to use delivery_method.