0
votes

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?

1

1 Answers

0
votes

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.