В предыдущей статье »Преимущества API для отправки почты перед SMTP в Ruby on Rails с помощью MailGun или SendGrid» я объяснил многие преимущества использования API перед SMTP.
В этой статье я расскажу об отправке электронных писем с помощью SendGrid SDK в Ruby on Rails, использовании динамических шаблонов SendGrid и даже включении вложений в письмо.
Добавление SendGrid SDK в Rails
В Gemfile добавьте официальный гем SendGrid:
gem 'sendgrid-ruby', '~> 6.6', '>= 6.6.2'
И запустите bundle install
.
Динамические шаблоны для SendGrid
Более надежной функцией SendGrid, на мой взгляд, является возможность добавления динамических шаблонов. Вы можете создать шаблон с помощью их визуального конструктора или с помощью HTML. В обоих случаях обеспечивается хороший отзывчивый предварительный просмотр письма, так что вы можете легко создавать красивые шаблоны.
Эти шаблоны также предоставляют возможности для замены. Например, вы создаете транзакционное письмо, и имя получателя зависит от человека, которому вы отправляете это письмо. Поэтому укажите переменную в шаблоне, например {{name}}
, и когда вы отправляете письмо через SDK, отправьте JSON-объект для подстановки значения, как показано ниже:
{
"name": "Sulman Baig"
}
Когда вы закончите создание шаблона, вы получите template_id
. Сохраните этот идентификатор для дальнейшего использования.
Получите API-ключ SendGrid:
Вы можете получить API-ключ SendGrid, выполнив действия, указанные в официальной документации: https://docs.sendgrid.com/ui/account-and-settings/api-keys#creating-an-api-key.
Отправьте задание по электронной почте:
Теперь, когда у вас есть template_id
и API Key
, давайте приступим к созданию задания электронной почты, которое будет отправлять письмо пользователю в базе данных, используя динамический шаблон и вложения.
Мы предполагаем использовать приведенный ниже фрагмент кода:
Теперь создайте файл app/jobs/email_job.rb
и добавьте следующий код.
Вы можете включить гем sidekiq и вызывать эту работу асинхронно.
# frozen_string_literal: true
require 'sendgrid-ruby'
#### Example Call
# EmailJob.new.perform(
# @user.id,
# { name: @user.name },
# ENV.fetch('EXPORT_TEMPLATE', nil),
# [
# {
# file: @tempfile.path,
# type: 'application/csv',
# name: @tempfile.path.split('/').last,
# content_id: 'export_file'
# }
# ]
# )
# This is the email job that will be sent to the user
class EmailJob
include SendGrid
# From Email and Name
NOREPLY_FROM_EMAIL = 'no-reply@allwallet.app'
NOREPLY_FROM_NAME = 'All Wallet'
# include sidekiq to call perform as perform_async
def perform(user_id, subsitutions, template_id, attachments = nil) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
# initialize sendgrid api
sg = SendGrid::API.new(api_key: ENV.fetch('SENDGRID_API_KEY', nil))
# we will get to_email from user object saved in db
user = User.kept.find_by(id: user_id)
return unless user
# initialize mail object of sendgrid
mail = Mail.new
# fill 'from' data from the constants mentioned above
mail.from = Email.new(email: NOREPLY_FROM_EMAIL, name: NOREPLY_FROM_NAME)
# personalization is object for email to data and templates
personalization = Personalization.new
# add user data to which email to be sent
personalization.add_to(Email.new(email: user.email, name: user.name))
# add substitutions to template created in sendgrid to replace the variable in template like `{{name}}`
# {
# "name": "Sulman Baig"
# }
personalization.add_dynamic_template_data(subsitutions)
mail.add_personalization(personalization)
mail.template_id = template_id
# If attachments are sent as arguments
if attachments.present? && attachments.is_a?(Array) && attachments.size.positive?
attachments.each do |attachment_input|
attachment = Attachment.new
# attachment has to be sent as base64 encoded string
attachment.content = Base64.strict_encode64(File.read(attachment_input[:file])) # file: path of file saved in local or remote
attachment.type = attachment_input[:type] # type of file e.g. application/csv
attachment.filename = attachment_input[:name] # filename
attachment.disposition = 'attachment'
attachment.content_id = attachment_input[:content_id] # e.g. export_file
mail.add_attachment(attachment)
end
end
begin
# Send Email
sg.client.mail._('send').post(request_body: mail.to_json)
rescue StandardError => e
# TODO: capture exception
end
end
end
GitHub Gist
Пример вызова вышеуказанного задания выглядит следующим образом:
EmailJob.new.perform(
@user.id,
{ name: @user.name },
ENV.fetch('EXPORT_TEMPLATE', nil),
[
{
file: @tempfile.path,
type: 'application/csv',
name: @tempfile.path.split('/').last,
content_id: 'export_file'
}
]
)
Счастливого кодинга!