I am trying to sending emails using MailGun's batch sending API using MailGun ruby sdk(https://github.com/mailgun/mailgun-ruby/blob/master/docs/MessageBuilder.md). As of now I have this method inside a class which inherits from ActionMailer.
class BatchMailer < ApplicationMailer
def send_batch_email(mail, recipients)
# First, instantiate the Mailgun Client with your API key
mg_client = Mailgun::Client.new("your-api-key")
# Create a Batch Message object, pass in the client and your domain.
mb_obj = Mailgun::BatchMessage.new(mg_client, "example.com")
# Define the from address.
mb_obj.from("[email protected]", {"first" => "Ruby", "last" => "SDK"});
# Define the subject.
mb_obj.subject("A message from the Ruby SDK using Message Builder!");
# Define the body of the message.
mb_obj.body_text("This is the text body of the message!");
# Loop through all of your recipients
mb_obj.add_recipient(:to, "[email protected]", {"first" => "John", "last" => "Doe"});
mb_obj.add_recipient(:to, "[email protected]", {"first" => "Jane", "last" => "Doe"});
mb_obj.add_recipient(:to, "[email protected]", {"first" => "Bob", "last" => "Doe"});
...
mb_obj.add_recipient(:to, "[email protected]", {"first" => "Sally", "last" => "Doe"});
# Call finalize to get a list of message ids and totals.
message_ids = mb_obj.finalize
# {'[email protected]' => 1000, '[email protected]' => 15}
end
end
Is is a correct way to keep the method that doesn't use actionmailer to send emails inside mailer?
ActionMailer method returns mail object but when trying to write spec for the method that uses API to send emails I can't able to get response as there won't be a mail object(ActionMailer message object). Where to keep this method and how it can be tested?
Is this a correct way to keep the method that doesn't use actionmailer to send emails inside mailer?
There is no reason to use a Mailer
in this case. Simply use a service object (a plain-old ruby object or PORO). It might look something like:
class BatchMailerService
attr_accessor *%w(
mail
recipients
recipient
).freeze
delegate *%w(
from
subject
body_text
add_recipient
finalize
), to: :mb_obj
delegate *%w(
address
first_name
last_name
), to: :recipient, prefix: true
class << self
def call(mail, recipients)
new(mail, recipients).call
end
end # Class Methods
#==============================================================================================
# Instance Methods
#==============================================================================================
def initialize(mail, recipients)
@mail, @recipients = mail, recipients
end
def call
setup_mail
add_recipients
message_ids = finalize
end
private
def mg_client
@mg_client ||= Mailgun::Client.new(ENV["your-api-key"])
end
def mb_obj
@mb_obj ||= Mailgun::BatchMessage.new(mg_client, "example.com")
end
def setup_mail
from("[email protected]", {"first" => "Ruby", "last" => "SDK"})
subject("A message from the Ruby SDK using Message Builder!")
body_text("This is the text body of the message!")
end
def add_recipients
recipients.each do |recipient|
@recipient = recipient
add_recipient(
:to,
recipient_address,
{
first: recipient_first_name,
last: recipient_last_name
}
)
end
end
end
Which you would use something like:
BatchMailerService.call(mail, recipients)
(assuming, naturally, that you have variables called mail
and recipients
).
Where to keep this method?
You might place that file in app/services/batch_mailer_service.rb
.
How can it be tested?
What do you mean? How you test the service depends on what your criteria for success are. You could test that mb_obj
receives the finalize
call (maybe using something like expect().to receive
). You could test message_ids
contains the correct information (maybe using something like expect().to include
). It sort of depends.