Emails with SendGrid Web API in Rails

Viewed 93

I'm following this tutorial: https://github.com/sendgrid/sendgrid-ruby/. Very straightforward. However, I want to avoid having a big chunk of code in my controller to send an email. It currently looks like this:

from = Email.new(email: 'some@email.com')
to = Email.new(email: 'some@email.com')
subject = 'Sending with SendGrid is Fun'
content = Content.new(type: 'text/plain', value: 'and easy to do anywhere, even with Ruby')
mail = Mail.new(from, subject, to, content)

sg = SendGrid::API.new(api_key: 'key')
response = sg.client.mail._('send').post(request_body: mail.to_json)

Ideally, I'd like to be able to trigger it from a service like: SendMail.new.perform() or some nice one-liner in the controller.

How would I abstract this code away from the controller and how would I call that new service/abstraction?

2 Answers

Twilio SendGrid developer evangelist here.

You can absolutely extract that from your controller, this is normally described as a service object.

I like to keep service objects in the app folder. You can do so by creating the directory app/services. Then create a file for the class, app/services/email_service.rb for example. In that file add the code to send the email, maybe something like this:

class EmailService
  def self.call(from:, to:, subject:, content:)
    self.new.send_email(from: from, to: to, subject: subject, content: 
  end

  def initialize()
    @sendgrid = SendGrid::API.new(api_key: Rails.application.credentials.sendgrid)
  end

  def send_email(from:, to:, subject:, content:)
    from = Email.new(email: from)
    to = Email.new(email: to)
    content = Content.new(type: 'text/plain', value: content)
    mail = Mail.new(from, subject, to, content)
    response = @sendgrid.client.mail._('send').post(request_body: mail.to_json)
  end
end

You can then call this service from your controller with the one liner:

EmailService.call(from: "me@mydomain.com", to: "you@yourdomain.com", subject: "My new email service", content: "It's pretty wonderful")

As a bonus, it's also easier to unit test the EmailService separate to the controller and to mock it out in controller tests.

If you are using rails, you can define it in your environment file and use one line code to send email from your controller.

production.rb

  config.action_mailer.delivery_method = :sendmail
   # Defaults to:
   # config.action_mailer.sendmail_settings = {
   #   location: '/usr/sbin/sendmail',
   #   arguments: '-i'
   # }
   config.action_mailer.perform_deliveries = true
   config.action_mailer.raise_delivery_errors = true
   config.action_mailer.default_options = {from: 'no-reply@example.com'}

and in your controller

   mail( :to => @user.email,
    :subject => 'Thanks for signing up for our amazing app' )

best case for using sendmail is using it with an ActionMailer class. You can look it up at rails documentation.

Related