class SesApi::Rails::Api

defines Mail::delivery_method

Constants

ALGO

constants

SERVICE
TERM_STR

Public Class Methods

new(values) click to toggle source
# File lib/ses_api/rails/api.rb, line 13
def initialize(values)
  self.settings = {
    }.merge!(values)

  self.conn = Faraday.new(:url => "https://#{SesApi::Rails.configuration.ses_endpoint}") do |faraday|
    faraday.request  :url_encoded             # form-encode POST params
    faraday.response :logger                  # log requests to STDOUT
    faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
  end
end

Public Instance Methods

build_destination_addresses(display_names) click to toggle source
# File lib/ses_api/rails/api.rb, line 86
def build_destination_addresses(display_names)
  to = mail.to.each_with_index.map { |email, i| "&Destination.ToAddresses.member.#{i+1}=#{format_email(email, display_names)}"}.join
  cc = mail.cc.each_with_index.map { |email, i| "&Destination.CcAddresses.member.#{i+1}=#{format_email(email, display_names)}"}.join if mail.cc.present?
  bcc = mail.bcc.each_with_index.map { |email, i| "&Destination.BccAddresses.member.#{i+1}=#{format_email(email, display_names)}"}.join if mail.bcc.present?
  return "#{to}#{cc}#{bcc}"
end
create_auth_header(request_datetime, credential_scope, hashed_payload, headers) click to toggle source
# File lib/ses_api/rails/api.rb, line 105
def create_auth_header(request_datetime, credential_scope, hashed_payload, headers)
   signing_key = create_signing_key(request_datetime)
   signed_headers = headers.sort.map { |k,v| "#{k.downcase}" }.join(";")
   string_to_sign = create_str_to_sign(request_datetime, credential_scope, headers, hashed_payload, signed_headers)
   signing_signature = create_signature(signing_key, string_to_sign)
   return "#{ALGO} Credential=#{SesApi::Rails.configuration.access_key_id}/#{credential_scope}, SignedHeaders=#{signed_headers}, Signature=#{signing_signature}"
 end
create_canonical_request(headers, hashed_payload, signed_headers) click to toggle source
# File lib/ses_api/rails/api.rb, line 97
def create_canonical_request(headers, hashed_payload, signed_headers)
  http_request_method = "POST"
  canonical_uri = "/"
  canonical_query_str = ""
  canonical_headers = headers.sort.map { |k,v| "#{k.downcase}:#{v.strip}\n"}.join
  canonical_request = [http_request_method, canonical_uri, canonical_query_str, canonical_headers, signed_headers, hashed_payload].join("\n")
end
create_credential_scope(request_datetime) click to toggle source
# File lib/ses_api/rails/api.rb, line 52
def create_credential_scope(request_datetime)
  "#{request_datetime[0,8]}/#{SesApi::Rails.configuration.aws_region}/#{SERVICE}/#{TERM_STR}"
end
create_datetime() click to toggle source
# File lib/ses_api/rails/api.rb, line 46
def create_datetime
  # returns ISO8601 Basic format YYYYMMDD'T'HHMMSS'Z'
  timestamp = Time.now.getutc
  timestamp.strftime('%Y%m%dT%H%M%SZ')
end
create_display_names() click to toggle source
# File lib/ses_api/rails/api.rb, line 73
def create_display_names
  display_names = {}
  mail.header.fields.each do |f|
    if %w[To From Cc Bcc].include? f.name
      f.address_list.addresses.each do |a|
        email = "#{a.local}@#{a.domain}"
        display_names.[]=(email, a.display_name) ? a.display_name.present? : a.local
      end
    end
  end
  display_names
end
create_payload() click to toggle source
# File lib/ses_api/rails/api.rb, line 56
def create_payload
  display_names = create_display_names
  destinations = build_destination_addresses(display_names)
  from = "&Source=#{format_email(mail.from[0], display_names)}"
  subject = "&Message.Subject.Data=#{CGI::escape(mail.subject)}"

  if mail.body.raw_source.present?
    body = "&Message.Body.Html.Data=#{CGI::escape(mail.body.raw_source)}&Message.Body.Html.Charset=UTF-8"
    body << "&Message.Body.Text.Data=#{CGI::escape(mail.body.raw_source)}&Message.Body.Text.Charset=UTF-8"
  else
    body = "&Message.Body.Html.Data=#{CGI::escape(mail.html_part.body.raw_source)}&Message.Body.Html.Charset=UTF-8"
    body << "&Message.Body.Text.Data=#{CGI::escape(mail.text_part.body.raw_source)}&Message.Body.Text.Charset=UTF-8"
  end

  payload = "AWSAccessKeyId=#{SesApi::Rails.configuration.access_key_id}&Action=SendEmail#{destinations}#{body}#{subject}#{from}"
end
create_signature(signing_key, string_to_sign) click to toggle source
# File lib/ses_api/rails/api.rb, line 125
def create_signature(signing_key, string_to_sign)
  hexhmac(signing_key, string_to_sign)
end
create_signing_key(request_datetime) click to toggle source
# File lib/ses_api/rails/api.rb, line 113
def create_signing_key(request_datetime)
  key_date = hmac("AWS4" + SesApi::Rails.configuration.secret_access_key, request_datetime[0,8])
  key_region = hmac(key_date, SesApi::Rails.configuration.aws_region)
  key_service = hmac(key_region, SERVICE)
  key_credentials = hmac(key_service, TERM_STR)
end
create_str_to_sign(request_datetime, credential_scope, headers, hashed_payload, signed_headers) click to toggle source
# File lib/ses_api/rails/api.rb, line 120
def create_str_to_sign(request_datetime, credential_scope, headers, hashed_payload, signed_headers)
  canonical_request = create_canonical_request(headers, hashed_payload, signed_headers)
  return "#{ALGO}\n#{request_datetime}\n#{credential_scope}\n#{Digest::SHA256.hexdigest(canonical_request)}"
end
deliver!(mail) click to toggle source
# File lib/ses_api/rails/api.rb, line 28
def deliver!(mail)
  self.mail = mail
  dt = create_datetime
  credential_scope = create_credential_scope(dt)

  response = conn.post do |req|
    req.body = create_payload
    hashed_payload = Digest::SHA256.hexdigest(req.body) #.downcase
    headers = { :'X-Amz-Date' => dt, Host: "#{SesApi::Rails.configuration.ses_endpoint}", :'X-Amz-Content-Sha256' => hashed_payload }
    headers.each do |addtl_header, value|
      req.headers[addtl_header.to_s.camelize] = value
    end
    req.headers['Authorization'] = create_auth_header(dt, credential_scope, hashed_payload, headers)
  end

  raise SesApi::Rails::SesError if response.status != 200
end
format_email(email, display_names) click to toggle source
# File lib/ses_api/rails/api.rb, line 93
def format_email(email, display_names)
  CGI::escape("#{display_names[email]}<#{email}>")
end
hexhmac(key, value) click to toggle source
# File lib/ses_api/rails/api.rb, line 133
def hexhmac(key, value)
  OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, value)
end
hmac(key, value) click to toggle source
# File lib/ses_api/rails/api.rb, line 129
def hmac(key, value)
  OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, value)
end
settings() click to toggle source
# File lib/ses_api/rails/api.rb, line 24
def settings
  {}
end