the-refinery/sparkpost_rails

How can I get a response from Sparkpost?

bajalovic opened this issue · 12 comments

After I send an email using:

result = MyMailer.some_message(some_var).deliver!

how can I get this response?

{"total_rejected_recipients"=>0, "total_accepted_recipients"=>1, "id"=>"00000000000000"}

The result variable is an instance of Mail::Message, so I can not get these values from that.

I need an id as I am using webhooks to track delivery, opens/clicks and so on...

Greetings @bajalovic!

Are you able to send the contents of your MyMailer#some_message method?

Hi @BradyBonnette

Basically I have some business logic and at the end:

sparkpost_options = {substitution_data: merge_vars, api_key: api_key}
result = mail(to: to_email,
                    from: "#{from_name} <#{from_email}>",
                    subject: subject,
                    body: message,
                    date: schedule_at,
                    sparkpost_data: sparkpost_options)

@bajalovic

Out of curiosity, did you set up the ActionMailer's delivery_method to use:sparkpost, as exampled by https://github.com/the-refinery/sparkpost_rails#getting-started ?

The reason I ask is because I was able to kinda replicate what you're doing by sending a non-SparkPost delivery method message (such as using ActionMailer through Google Mail) using roughly the same Mailer code as you. The result for me when using a non-SparkPost delivery method was that #deliver! (and variants such as #deliver_now!) method returned a Mail::Message instead of a hash when the message was successfully delivered through Google Mail.

@BradyBonnette
I did setup delivery_method to use :sparkpost

@bajalovic

Are you setting the delivery_method in all relevant config/environments/*.rb files? For example, if you have delivery_method set to :sparkpost in config/environments/production.rb, and you don't have it set in config/environments/development.rb, and you're currently testing your Mailer code out in development, then the SparkPost backend would not get picked up.

@BradyBonnette

I have this setup in development.rb:

config.action_mailer.delivery_method = :sparkpost

@bajalovic

In your MyMailer#some_message method, what happens if you try this:

sparkpost_options = {substitution_data: merge_vars, api_key: api_key}
result = mail(to: to_email,
                    from: "#{from_name} <#{from_email}>",
                    subject: subject,
                    body: message,
                    date: schedule_at,
                    sparkpost_data: sparkpost_options,
                    delivery_method: :sparkpost)

Note the last option for delivery_method: :sparkpost.

@BradyBonnette result is still an instance of Mail::Message

This is the result from puts result.inspect

#<Mail::Message:70095412235940, Multipart: false, Headers: <Date: Wed, 20 Jul 2016 22:26:17 +0000> .........

@bajalovic

What was the return value of #deliver! being called on that new result where you supplied the delivery_method: :sparkpost option to #mail?

In other words, did the result of MyMailer.some_message(some_var).deliver! change when you supplied the delivery_method option?

EDIT: Oh, I think I got confused. when you say puts result.inspect, are you referring to the result coming from result = mail(to: ...), or are you referring to the result coming from MyMailer.some_message(some_var).deliver!

This might be related: There are different behaviors when calling deliver_now!/deliver! vs deliver_now/deliver. deliver_now! and deliver! will return the response, while deliver_now and deliver will return the Mail::Message instance.

I tracked it down to a difference in how the mail gem supports the return_response option (it's honored when calling deliver! but ignored for calls to deliver).

A potential workaround if you need to use the deliver/deliver_now option would be to retrieve the response by calling mail.delivery_method.response. Something like this:

mail = MyMailer.some_message(some_var)
mail.deliver_now
result = mail.delivery_method.response

@petesharum

Thanks for that insight! I checked it out in my test environment, and sure enough you are right.

Using #deliver / #deliver_now, I saw:

2.1.5 :001 > message = MyMailer.send_test.deliver
DEPRECATION WARNING: `#deliver` is deprecated and will be removed in Rails 5. Use `#deliver_now` to deliver immediately or `#deliver_later` to deliver through Active Job. (called from irb_binding at (irb):1)
  Rendered text template (0.0ms)

MyMailer#send_test: processed outbound mail in 3373.3ms

Sent mail to <redacted> (473.0ms)
Date: Fri, 22 Jul 2016 10:17:22 -0400
From: from@example.com
To: <redacted>
Message-ID: <57922af2e1a84_328ddd72f095cc@redacted.mail>
Subject: Send test
Mime-Version: 1.0
Content-Type: text/plain;
 charset=UTF-8
Content-Transfer-Encoding: 7bit
sparkpost-data: {:template_id=>"my-first-email"}


 => #<Mail::Message:55283580, Multipart: false, Headers: <Date: Fri, 22 Jul 2016 10:17:22 -0400>, <From: from@example.com>, <To: redacted>, <Message-ID: <57922af2e1a84_328ddd72f095cc@redacted.mail>>, <Subject: Send test>, <Mime-Version: 1.0>, <Content-Type: text/plain>, <Content-Transfer-Encoding: 7bit>, <sparkpost-data: {:template_id=>"my-first-email"}>> 
2.1.5 :002 > 

2.1.5 :022 > message.delivery_method.response
 => {"total_rejected_recipients"=>0, "total_accepted_recipients"=>1, "id"=>"48352743735133856"} 
2.1.5 :023 > 

Using #deliver! / #deliver_now!, I saw:

2.1.5 :036 >   message = MyMailer.send_test.deliver!
DEPRECATION WARNING: `#deliver!` is deprecated and will be removed in Rails 5. Use `#deliver_now!` to deliver immediately or `#deliver_later!` to deliver through Active Job. (called from irb_binding at (irb):36)
  Rendered text template (0.0ms)

MyMailer#send_test: processed outbound mail in 1611.0ms
 => {"total_rejected_recipients"=>0, "total_accepted_recipients"=>1, "id"=>"48352743735165983"} 
2.1.5 :037 > 

This is really good to know. The only thing that is still confusing me is that @bajalovic is using #deliver! and still getting a Mail::Message returned from his Mailer method.

Ah i tested and tested and then noticed a problem.

The json

{"total_rejected_recipients"=>0, "total_accepted_recipients"=>1, "id"=>"48352743735165983"}

is the result of deliver_now! method and not the result of mail() method (if you see my first comment, i expected that mail method returns a json, but it always returns a Mail::Message object instance.

I had to refactor a so to expect the result json not inside a mailer, and it is working fine.

Thank you both @BradyBonnette and @petesharum for your efforts.