class SendGridActionMailer::DeliveryMethod

Constants

DEFAULTS
SendgridDeliveryError

TODO: use custom class to customer excpetion payload

Attributes

options[RW]
settings[RW]

Public Class Methods

new(params = {}) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 19
def initialize(params = {})
  self.settings = DEFAULTS.merge(params)
end

Private Class Methods

transform_keys(object) { |key| ... } click to toggle source

Recursive key transformation based on Rails deep_transform_values

# File lib/sendgrid_actionmailer.rb, line 304
def self.transform_keys(object, &block)
  case object
  when Hash
    object.map { |key, value| [yield(key), transform_keys(value, &block)] }.to_h
  when Array
    object.map { |e| transform_keys(e, &block) }
  else
    object
  end
end

Public Instance Methods

deliver!(mail) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 23
def deliver!(mail)
  self.options = {}
  sendgrid_mail = Mail.new.tap do |m|
    m.from = to_email(mail.from)
    m.reply_to = to_email(mail.reply_to)
    m.subject = mail.subject || ""
  end

  add_personalizations(sendgrid_mail, mail)
  add_options(sendgrid_mail, mail)
  add_content(sendgrid_mail, mail)
  add_send_options(sendgrid_mail, mail)
  add_mail_settings(sendgrid_mail, mail)
  add_tracking_settings(sendgrid_mail, mail)

  if (settings[:perform_send_request] == false)
    response = sendgrid_mail
  else
    response = perform_send_request(sendgrid_mail)
  end

  settings[:return_response] ? response : self
end

Private Instance Methods

add_attachments(sendgrid_mail, mail) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 163
def add_attachments(sendgrid_mail, mail)
  mail.attachments.each do |part|
    sendgrid_mail.add_attachment(to_attachment(part))
  end
end
add_content(sendgrid_mail, mail) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 169
def add_content(sendgrid_mail, mail)
  if mail['template_id']
    # We are sending a template, so we don't need to add any content outside
    # of attachments
    add_attachments(sendgrid_mail, mail)
  else
    case mail.mime_type
    when 'text/plain'
      sendgrid_mail.add_content(to_content(:plain, mail.body.decoded))
    when 'text/html'
      sendgrid_mail.add_content(to_content(:html, mail.body.decoded))
    when 'multipart/alternative', 'multipart/mixed', 'multipart/related'
      sendgrid_mail.add_content(to_content(:plain, mail.text_part.decoded)) if mail.text_part
      sendgrid_mail.add_content(to_content(:html, mail.html_part.decoded)) if mail.html_part

      add_attachments(sendgrid_mail, mail)
    end
  end
end
add_mail_settings(sendgrid_mail, mail) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 247
def add_mail_settings(sendgrid_mail, mail)
  local_settings = mail['mail_settings'] && mail['mail_settings'].unparsed_value || {}
  global_settings = self.settings[:mail_settings] || {}
  settings = global_settings.merge(local_settings)
  unless settings.empty?
    sendgrid_mail.mail_settings = MailSettings.new.tap do |m|
      if settings[:bcc]
        m.bcc = BccSettings.new(**settings[:bcc])
      end
      if settings[:bypass_list_management]
        m.bypass_list_management = BypassListManagement.new(**settings[:bypass_list_management])
      end
      if settings[:footer]
        m.footer = Footer.new(**settings[:footer])
      end
      if settings[:sandbox_mode]
        m.sandbox_mode = SandBoxMode.new(**settings[:sandbox_mode])
      end
      if settings[:spam_check]
        m.spam_check = SpamCheck.new(**settings[:spam_check])
      end
    end
  end
end
add_options(sendgrid_mail, mail) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 156
def add_options(sendgrid_mail, mail)
  self.options.merge!(**self.class.transform_keys(self.settings, &:to_sym))
  if !!(mail['delivery-method-options'])
    self.options.merge!(**self.class.transform_keys(mail['delivery-method-options'].unparsed_value , &:to_sym))
  end
end
add_personalizations(sendgrid_mail, mail) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 189
def add_personalizations(sendgrid_mail, mail)
  if mail['personalizations']
    mail['personalizations'].unparsed_value.each do |p|
      sendgrid_mail.add_personalization(setup_personalization(mail, p))
    end
  end
  if (mail.to && !mail.to.empty?) || (mail.cc && !mail.cc.empty?) || (mail.bcc && !mail.bcc.empty?)
    personalization = setup_personalization(mail, {})
    to_emails(mail.to).each { |to| personalization.add_to(to) }
    to_emails(mail.cc).each { |cc| personalization.add_cc(cc) }
    to_emails(mail.bcc).each { |bcc| personalization.add_bcc(bcc) }
    sendgrid_mail.add_personalization(personalization)
  end
end
add_send_options(sendgrid_mail, mail) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 204
def add_send_options(sendgrid_mail, mail)
  if mail['template_id']
     sendgrid_mail.template_id = mail['template_id'].to_s
  end
  if mail['sections']
    mail['sections'].unparsed_value.each do |key, value|
      sendgrid_mail.add_section(Section.new(key: key, value: value))
    end
  end
  if mail['headers']
    mail['headers'].unparsed_value.each do |key, value|
      sendgrid_mail.add_header(Header.new(key: key, value: value))
    end
  end
  if mail['categories']
    mail['categories'].value.split(",").each do |value|
      sendgrid_mail.add_category(Category.new(name: value.strip))
    end
  end
  if mail['custom_args']
    mail['custom_args'].unparsed_value.each do |key, value|
      sendgrid_mail.add_custom_arg(CustomArg.new(key: key, value: value))
    end
  end
  if mail['send_at']
    sendgrid_mail.send_at = mail['send_at'].value.to_i
  end
  if mail['batch_id']
    sendgrid_mail.batch_id = mail['batch_id'].to_s
  end
  if mail['asm']
    asm = mail['asm'].unparsed_value
    asm =  asm.delete_if { |key, value| 
      !key.to_s.match(/(group_id)|(groups_to_display)/) }
    if asm.keys.map(&:to_s).include?('group_id')
      sendgrid_mail.asm = ASM.new(**self.class.transform_keys(asm, &:to_sym))
    end
  end
  if mail['ip_pool_name']
    sendgrid_mail.ip_pool_name = mail['ip_pool_name'].to_s
  end
end
add_tracking_settings(sendgrid_mail, mail) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 272
def add_tracking_settings(sendgrid_mail, mail)
  if mail['tracking_settings']
    settings = mail['tracking_settings'].unparsed_value
    sendgrid_mail.tracking_settings = TrackingSettings.new.tap do |t|
      if settings[:click_tracking]
        t.click_tracking = ClickTracking.new(**settings[:click_tracking])
      end
      if settings[:open_tracking]
        t.open_tracking = OpenTracking.new(**settings[:open_tracking])
      end
      if settings[:subscription_tracking]
        t.subscription_tracking = SubscriptionTracking.new(**settings[:subscription_tracking])
      end
      if settings[:ganalytics]
        t.ganalytics = Ganalytics.new(**settings[:ganalytics])
      end
    end
  end
end
client() click to toggle source
# File lib/sendgrid_actionmailer.rb, line 55
def client
  @client = SendGrid::API.new(**client_options).client
end
client_options() click to toggle source
# File lib/sendgrid_actionmailer.rb, line 49
def client_options
  options.dup
  .select { |key, value| key.to_s.match(/(api_key|host|request_headers|version|impersonate_subuser)/) }
  .merge(http_options: settings.fetch(:http_options, {}))
end
get_disposition(message) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 149
def get_disposition(message)
  return if message.header.nil?
  content_disp = message.header[:content_disposition]
  return unless content_disp.respond_to?(:disposition_type)
  content_disp.disposition_type
end
perform_send_request(email) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 292
def perform_send_request(email)
  result = client.mail._('send').post(request_body: email.to_json) # ლ(ಠ益ಠლ) that API

  if result.status_code && result.status_code.start_with?('4')
    full_message = "Sendgrid delivery failed with #{result.status_code}: #{result.body}"
    settings[:raise_delivery_errors] ? raise(SendgridDeliveryError, full_message) : warn(full_message)
  end

  result
end
setup_personalization(mail, personalization_hash) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 88
def setup_personalization(mail, personalization_hash)
  personalization = Personalization.new

  personalization_hash =  self.class.transform_keys(personalization_hash, &:to_s)

  (personalization_hash['to'] || []).each do |to|
    personalization.add_to Email.new(email: to['email'], name: to['name'])
  end
  (personalization_hash['cc'] || []).each do |cc|
    personalization.add_cc Email.new(email: cc['email'], name: cc['name'])
  end
  (personalization_hash['bcc'] || []).each do |bcc|
    personalization.add_bcc Email.new(email: bcc['email'], name: bcc['name'])
  end
  (personalization_hash['headers'] || []).each do |header_key, header_value|
    personalization.add_header Header.new(key: header_key, value: header_value)
  end
  (personalization_hash['substitutions'] || {}).each do |sub_key, sub_value|
    personalization.add_substitution(Substitution.new(key: sub_key, value: sub_value))
  end
  (personalization_hash['custom_args'] || {}).each do |arg_key, arg_value|
    personalization.add_custom_arg(CustomArg.new(key: arg_key, value: arg_value))
  end
  if personalization_hash['send_at']
    personalization.send_at = personalization_hash['send_at']
  end
  if personalization_hash['subject']
    personalization.subject = personalization_hash['subject']
  end

  if mail['dynamic_template_data'] || personalization_hash['dynamic_template_data']
    if mail['dynamic_template_data']
      data = mail['dynamic_template_data'].unparsed_value
      data.merge!(personalization_hash['dynamic_template_data'] || {})
    else
      data = personalization_hash['dynamic_template_data']
    end
    personalization.add_dynamic_template_data(data)
  elsif mail['template_id'].nil?
    personalization.add_substitution(Substitution.new(key: "%asm_group_unsubscribe_raw_url%", value: "<%asm_group_unsubscribe_raw_url%>"))
    personalization.add_substitution(Substitution.new(key: "%asm_global_unsubscribe_raw_url%", value: "<%asm_global_unsubscribe_raw_url%>"))
    personalization.add_substitution(Substitution.new(key: "%asm_preferences_raw_url%", value: "<%asm_preferences_raw_url%>"))
  end

  return personalization
end
to_attachment(part) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 135
def to_attachment(part)
  Attachment.new.tap do |a|
    a.content = Base64.strict_encode64(part.body.decoded)
    a.type = part.mime_type
    a.filename = part.filename

    disposition = get_disposition(part)
    a.disposition = disposition unless disposition.nil?

    has_content_id = part.header && part.has_content_id?
    a.content_id = part.header['content_id'].field.content_id if has_content_id
  end
end
to_content(type, value) click to toggle source

type should be either :plain or :html

# File lib/sendgrid_actionmailer.rb, line 60
def to_content(type, value)
  Content.new(type: "text/#{type}", value: value)
end
to_email(input) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 64
def to_email(input)
  to_emails(input).first
end
to_emails(input) click to toggle source
# File lib/sendgrid_actionmailer.rb, line 68
def to_emails(input)
  if input.is_a?(String)
    [Email.new(email: input)]
  elsif input.is_a?(::Mail::AddressContainer) && !input.instance_variable_get('@field').nil?
    input.instance_variable_get('@field').addrs.map do |addr| # Mail::Address
      Email.new(email: addr.address, name: addr.name)
    end
  elsif input.is_a?(::Mail::AddressContainer)
    input.map do |addr|
      Email.new(email: addr)
    end
  elsif input.is_a?(::Mail::StructuredField)
    [Email.new(email: input.value)]
  elsif input.nil?
    []
  else
    puts "unknown type #{input.class.name}"
  end
end