How to subscribe users to SendGrid’s marketing emails using Rails
Tags: rails, sendgrid, sidekiq
Published: 2023-02-13 05:00:00

SendGrid is a well-known email delivery platform enabling businesses to send and manage their email campaigns and transactional emails easily. Its APIs make integrating with a Rails web application a breeze. This article will guide you through how to subscribe users to SendGrid’s marketing emails using Rails.

## Step 1: Create a SendGrid account: 
To get started, you need to create a SendGrid account. Depending on your requirements, you can sign up for a free account or choose a paid plan. Once you have created your account, you will have access to the SendGrid Dashboard where you can manage your email campaigns and monitor the performance of your emails.

## Step 2: Install the SendGrid Ruby gem:

To integrate SendGrid with your Rails application, you need to install the SendGrid Ruby gem. You can add the following line to your Gemfile and run the `bundle install` command.

```ruby
gem 'sendgrid-ruby'
```

## Step 3: Configure the SendGrid API key:

Once you have installed the SendGrid Ruby gem, you must configure your SendGrid API key. You can find your API key in the SendGrid Dashboard under “Settings” -\> “API Keys”. To configure your API key in your Rails application, you can create a secret in credentials by running the following command:

```bash
EDITOR="nano" bin/rails credentials:edit
```

Then add the following code to the file:

```yaml
sendgrid:
  api_key: "YOUR_API_KEY"
```

Save the file once you have added your API key.

## Step 4: Create a new marketing list:

In SendGrid, go to “Marketing” -\> “Contacts” -\> “Create” -\> “New List”. Enter the name of your list and save it. Once the list is created, open it, and copy the LIST ID from the URL `lists/LIST_ID`. Save the LIST ID in your initializer file or your Ruby code.

## Step 5: SendGrid base class:

To make it easier to use SendGrid for various purposes, such as sending transactional emails, subscribing, and unsubscribing, it’s recommended to create a base class in the `lib` folder. This class will contain the constant `LIST_ID`, where you can add your default list ID and methods to get the model class, SendGrid API key, and SendGrid instance.

```ruby
# lib/sendgrid/base.rb
require 'sendgrid-ruby'

module Sendgrid
  # @note: This class is used to define the base class for SendGrid.
  class Base
    include SendGrid

    LIST_ID = "YOUR_LIST_ID"

    # @note: This method is used to get the model class.
    # @param [String] model The model name.
    # @return [Class] The model class.
    def model_class(model)
      model.constantize
    end

    # @note: This method is used to get the SendGrid API key.
    # @return [String] The SendGrid API key.
    def sendgrid_api_key
      @sendgrid_api_key ||= Rails.application.credentials.dig(:sendgrid, :api_key)
    end

    # @note: This method is used to get the SendGrid instance.
    # @return [SendGrid::API] The SendGrid instance.
    def sg_instance
      @sg_instance ||= SendGrid::API.new(api_key: sendgrid_api_key)
    end
  end

  class Error < StandardError; end
end
```

This class contains the constant of `LIST_ID`, where you can add your default list id.

`model_class` is used for multiple models like polymorphism, so we can use it for the user and other contact models.

## Step 6: Sendgrid subscribe background job:

Now to the important stuff of actually subscribing a model instance to the marketing list:

```ruby
# lib/sendgrid/subscribe.rb
module Sendgrid
  # @note: This class defines the class for SendGrid subscription.
  class Subscribe < Sendgrid::Base
    include ::Sidekiq::Worker
    sidekiq_options queue: :low, retry: 1

    # @note: This method subscribes a user to a list in SendGrid.
    # @param [String] model The model name.
    # @param [Integer] id The model id.
    # @param [String] list_id The list id.
    # @return [Array] Job ID.
    # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
    def perform(model, id, list_id = Sendgrid::Base::LIST_ID)
      return if Rails.env.test?

      record = model_class(model).find_by(id:)
      return unless record

      data = {
        list_ids: [list_id],
        contacts: [
          {
            email: record.email,
            first_name: record.name
          }
        ]
      }
      # https://docs.sendgrid.com/api-reference/contacts/add-or-update-a-contact
      response = sg_instance.client.marketing.contacts.put(request_body: data)
      Rails.logger.info "'Sendgrid::Subscribe' response: #{response.status_code} - #{response.body}"
      raise Sendgrid::Error, response.body if response.status_code != '202'

    end

    # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
  end
end
```

The perform method is the main method that subscribes a user to a list in SendGrid. It takes three arguments: model, id, and `list_id`. model is the name of the model, id is the model's id, and `list_id` is the id of the list to subscribe the user to. If `list_id` is not specified, the `LIST_ID` constant from the `Sendgrid::Base` class is used.

The method first checks if the current environment is the test environment and returns if it is. It then retrieves the record of the specified model with the specified id and returns if it is not found. If the record is found, the data is prepared with the email and name of the user and the list id. This data is then sent to SendGrid's API to subscribe the user to the specified list.

The response from the API is logged, and an error is raised if the status code is not 202, which indicates a successful subscription.

## Step 7: Call the Subscribe Job:

To subscribe a user to the marketing list, a method `subscribe_to_sendgrid` should be added to the user model. This method calls the `perform_async` method from the `Sendgrid::Subscribe` class, passing the class name of the user model and its id as arguments.

Finally, this method can be called in the `after_create` callback, so whenever a new user is created, they will be automatically subscribed to the marketing list.

```ruby
# @note: This method is used to subscribe the user to SendGrid.
# @return [void]
def subscribe_to_sendgrid
  Sendgrid::Subscribe.perform_async(self.class.to_s, id)
end
```

---- 
Happy Coding!

Contact me at [sulman@hey.com](mailto:sulman@hey.com)