sendgrid-actionmailer 0.2.1 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 279c424c1fb91a3d43959b079eb62ff18cc49f4b
4
- data.tar.gz: 612acbbe466f59ef1cfe8fb43d3e50b905b480c7
3
+ metadata.gz: 92aceed9d68cf14a3c461fef95478935b2d6abad
4
+ data.tar.gz: cda4360a31bddc4dbc8dd02b1ad6bf96519b1f84
5
5
  SHA512:
6
- metadata.gz: efa913396a27fca27aaa83f3aa4ee00f9c59a8e5706d881d097e43e7a2d246fb06283f6c58a41ebe468fd997a6b2b7e56fe43b444597c31fe465bfaca2ff007e
7
- data.tar.gz: 22c1f0dc2f693e4788cd508ccb2a4a7997e4437423ceea8c6eeaf5372dd2905c52447660dd0590f548f1f17dc2faa07410f3efebe1732af47a587502b88702fc
6
+ metadata.gz: 7687cc4ede183737d615e2892844f1ac538e8b629f74952fd584761a81207c32fdcc44cd031898bc00996edc8a2eb13dbe5c01cbaf4bf951c2f31532d99c553e
7
+ data.tar.gz: e63c5d2236e329ab7b7898875c0d87fa2ffa34565e9b0ddbd58aa70753be615a4ea22a428b20f4e879e9b97cb0ac50209f3b5dfff80a825863a51c084fc1fdfc
@@ -1,11 +1,14 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.2.1
5
- - 2.0.0
6
- - 1.9.3
7
- before_script:
8
- - bundle install
4
+ - 2.5.1
5
+ - 2.4.4
6
+ - 2.3.4
7
+ - 2.3.7
8
+ - 2.2.10
9
+ before_install:
10
+ - gem install bundler
9
11
  gemfile:
10
12
  - gemfiles/mail_2.5.gemfile
11
13
  - gemfiles/mail_2.6.gemfile
14
+ - gemfiles/mail_2.7.gemfile
data/Appraisals CHANGED
@@ -5,3 +5,7 @@ end
5
5
  appraise "mail-2.6" do
6
6
  gem "mail", "2.6.4"
7
7
  end
8
+
9
+ appraise "mail-2.7" do
10
+ gem "mail", "2.7.0"
11
+ end
@@ -1,5 +1,11 @@
1
1
  # Change Log
2
2
 
3
+ ## 2.0.0 - 2018-08-15
4
+
5
+ ### Changed
6
+
7
+ - Compatibility with `sendgrid-ruby` v5.0.
8
+
3
9
  ## 0.2.1 - 2016-04-26
4
10
 
5
11
  ### Fixed
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in sendgrid-actionmailer.gemspec
4
4
  gemspec
5
+
6
+ if RUBY_VERSION < '2'
7
+ gem 'public_suffix', '~> 1.4.6'
8
+ gem 'mime-types', '~> 2.99'
9
+ end
data/README.md CHANGED
@@ -1,23 +1,12 @@
1
1
  # SendGrid ActionMailer
2
2
 
3
- An ActionMailer adapter to send email using SendGrid's HTTPS Web API (instead of SMTP).
4
-
5
- [![BuildStatus](https://travis-ci.org/eddiezane/sendgrid-actionmailer.svg?branch=master)](https://travis-ci.org/eddiezane/sendgrid-actionmailer)
3
+ An ActionMailer adapter to send email using SendGrid's HTTPS Web API (instead of SMTP). Compatible with Rails 5 and Sendgrid API v3.
6
4
 
7
5
  ## Installation
8
6
 
9
7
  Add this line to your application's Gemfile:
10
8
 
11
- gem 'sendgrid-actionmailer'
12
-
13
- And then execute:
14
-
15
- $ bundle
16
-
17
- Or install it yourself as:
18
-
19
- $ gem install sendgrid-actionmailer
20
-
9
+ gem 'sendgrid-actionmailer', github: 'eddiezane/sendgrid-actionmailer'
21
10
 
22
11
  ## Usage
23
12
 
@@ -26,74 +15,210 @@ Create a [SendGrid API Key](https://app.sendgrid.com/settings/api_keys) for your
26
15
  ```ruby
27
16
  config.action_mailer.delivery_method = :sendgrid_actionmailer
28
17
  config.action_mailer.sendgrid_actionmailer_settings = {
29
- api_key: ENV['SENDGRID_API_KEY']
18
+ api_key: ENV['SENDGRID_API_KEY'],
19
+ raise_delivery_errors: true
30
20
  }
31
21
  ```
32
22
 
33
23
  Normal ActionMailer usage will now transparently be sent using SendGrid's Web API.
34
24
 
35
- ### X-SMTPAPI
25
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body')```
26
+
27
+ ### Dynamic API Key
28
+
29
+ If you need to send mail for a number of Sendgrid accounts, you can set the API key for these as follows:
36
30
 
37
- You may optionally set SendGrid's [X-SMTPAPI](https://sendgrid.com/docs/API_Reference/SMTP_API/index.html) header on messages to control SendGrid specific functionality. This header must be set to a JSON string.
38
31
 
39
32
  ```ruby
40
- class UserMailer < ApplicationMailer
41
- def welcome_email(user)
42
- headers['X-SMTPAPI'] = {
43
- category: ['newuser']
44
- }.to_json
45
-
46
- mail(to: user.email, subject: 'Welcome to My Awesome Site')
47
- end
48
- end
33
+ mail(to: 'example@email.com',
34
+ subject: 'email subject',
35
+ body: 'email body',
36
+ delivery_method_options: {
37
+ api_key: 'SENDGRID_API_KEY'
38
+ })
49
39
  ```
50
40
 
51
- The following `X-SMTPAPI` options are supported:
41
+ ## SendGrid Mail Extensions
52
42
 
53
- - `filters`
54
- - `category`
55
- - `send_at`
56
- - `send_each_at`
57
- - `section`
58
- - `sub`
59
- - `asm_group_id`
60
- - `unique_args`
61
- - `ip_pool`
43
+ The Mail functionality is extended to include additional attributes provided by the Sendgrid API.
62
44
 
63
- #### X-SMTPAPI Defaults
45
+ [Sendgrid v3 API Documentation](https://sendgrid.com/docs/API_Reference/api_v3.html)
64
46
 
65
- Default values for the `X-SMTPAPI` header may be set at different levels using ActionMailer's normal options for setting default headers. However, since `X-SMTPAPI` is treated as a single string value, it's important to note that default values at different levels will not get merged together. So if you override the `X-SMTPAPI` header at any level, you may need to repeat any default values at more specific levels.
47
+ ### template_id (string)
48
+ The id of a template that you would like to use. If you use a template that contains a subject and content (either text or html), you do not need to specify those at the personalizations nor message level.
66
49
 
67
- Global defaults can be set inside `config/application.rb`:
50
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', template_id: 'template_1')```
68
51
 
69
- ```ruby
70
- config.action_mailer.default_options = {
71
- 'X-SMTPAPI' => {
72
- ip_pool: 'marketing_ip_pool'
73
- }.to_json
74
- }
75
- ```
52
+ ### sections (object)
53
+ An object of key/value pairs that define block sections of code to be used as substitutions.
76
54
 
77
- Per-mailer defaults can be set inside an ActionMailer class:
55
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', sections: {'%header%' => "<h1>Header</h1>"})```
78
56
 
79
- ```ruby
80
- class NewsletterMailer < ApplicationMailer
81
- default('X-SMTPAPI' => {
82
- category: ['newsletter'],
83
-
84
- # Assuming the above "config.action_mailer.default_options" global default
85
- # example, the default "ip_pool" value must be repeated here if you want
86
- # that default value to also apply to this specific mailer that's
87
- # specifying it's own default X-SMTPAPI value.
88
- ip_pool: 'marketing_ip_pool'
89
- }.to_json)
90
- end
91
- ```
57
+ ### headers (object)
58
+ An object containing key/value pairs of header names and the value to substitute for them. You must ensure these are properly encoded if they contain unicode characters. Must not be one of the reserved headers.
59
+
60
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', headers: {'X-CUSTOM-HEADER' => "foo"})```
61
+
62
+ ### categories (array)
63
+ An array of category names for this message. Each category name may not exceed 255 characters.
64
+
65
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', categories: ['marketing', 'sales'])```
66
+
67
+ ### custom_args (object)
68
+ Values that are specific to the entire send that will be carried along with the email and its activity data. Substitutions will not be made on custom arguments, so any string that is entered into this parameter will be assumed to be the custom argument that you would like to be used. This parameter is overridden by personalizations[x].custom_args if that parameter has been defined. Total custom args size may not exceed 10,000 bytes.
69
+
70
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', custom_args: {campaign: 'welcome'})```
71
+
72
+ ### send_at (integer)
73
+ A unix timestamp allowing you to specify when you want your email to be delivered. This may be overridden by the personalizations[x].send_at parameter. You can't schedule more than 72 hours in advance. If you have the flexibility, it's better to schedule mail for off-peak times. Most emails are scheduled and sent at the top of the hour or half hour. Scheduling email to avoid those times (for example, scheduling at 10:53) can result in lower deferral rates because it won't be going through our servers at the same times as everyone else's mail.
74
+
75
+ ### batch_id (string)
76
+ This ID represents a batch of emails to be sent at the same time. Including a batch_id in your request allows you include this email in that batch, and also enables you to cancel or pause the delivery of that batch. For more information, see [cancel_schedule_send](https://sendgrid.com/docs/API_Reference/Web_API_v3/cancel_schedule_send.html)
77
+
78
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', send_at: 1443636842, batch_id: 'batch1')```
79
+
80
+ ### asm (object)
81
+ An object allowing you to specify how to handle unsubscribes.
82
+
83
+ #### group_id (integer) *required
84
+ The unsubscribe group to associate with this email.
85
+
86
+ #### groups_to_display (array[integer])
87
+ An array containing the unsubscribe groups that you would like to be displayed on the unsubscribe preferences page.
88
+
89
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', asm: group_id: 99, groups_to_display: [4,5,6,7,8])```
90
+
91
+ ### ip_pool_name (string)
92
+ The IP Pool that you would like to send this email from.
93
+
94
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', ip_pool_name: 'marketing_ips')```
95
+
96
+ ### mail_settings (object)
97
+ A collection of different mail settings that you can use to specify how you would like this email to be handled.
98
+
99
+ #### bcc (object)
100
+ This allows you to have a blind carbon copy automatically sent to the specified email address for every email that is sent.
101
+
102
+ ##### enable (boolean)
103
+ Indicates if this setting is enabled.
104
+
105
+ ##### email (string)
106
+ The email address that you would like to receive the BCC.
107
+
108
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', mail_settings: {bcc: {enable: true, email: 'bcc@example.com}})```
109
+
110
+ #### bypass_list_management (object)
111
+ Allows you to bypass all unsubscribe groups and suppressions to ensure that the email is delivered to every single recipient. This should only be used in emergencies when it is absolutely necessary that every recipient receives your email.
112
+
113
+ ###### enable (boolean)
114
+ Indicates if this setting is enabled.
115
+
116
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', mail_settings:{ bypass_list_management: { enable: true }})```
117
+
118
+ #### footer (object)
119
+ The default footer that you would like included on every email.
120
+
121
+ ##### enable (boolean)
122
+ Indicates if this setting is enabled.
123
+
124
+ ##### text (string)
125
+ The plain text content of your footer.
126
+
127
+ ##### html (string)
128
+ The HTML content of your footer.
129
+
130
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', mail_settings:{ footer: { enable: true, text: 'FOOTER', html: '<h1>FOOTER</h1>' }})```
131
+
132
+ #### sandbox_mode (object)
133
+ This allows you to send a test email to ensure that your request body is valid and formatted correctly.
134
+
135
+ ##### enable (boolean)
136
+ Indicates if this setting is enabled.
137
+
138
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', mail_settings:{ sandbox_mode: { enable: true }})```
139
+
140
+ #### spam_check (object)
141
+ This allows you to test the content of your email for spam.
142
+
143
+ ##### enable (boolean)
144
+ Indicates if this setting is enabled.
145
+
146
+ ##### threshold (integer)
147
+ The threshold used to determine if your content qualifies as spam on a scale from 1 to 10, with 10 being most strict, or most likely to be considered as spam.
148
+
149
+ ##### post_to_url (string)
150
+ An Inbound Parse URL that you would like a copy of your email along with the spam report to be sent to.
151
+
152
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', mail_settings:{ spam_check: {enable: true, threshold: 1, post_to_url: 'https://spamcatcher.sendgrid.com'}})```
153
+ ### tracking_settings(json)
154
+ Settings to determine how you would like to track the metrics of how your recipients interact with your email.
155
+
156
+ #### click_tracking(object)
157
+ Allows you to track whether a recipient clicked a link in your email.
158
+
159
+ ##### enable (boolean)
160
+ Indicates if this setting is enabled.
161
+
162
+ ##### enable_text (boolean)
163
+ Indicates if this setting should be included in the text/plain portion of your email.
164
+
165
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', tracking_settings:{ enable: false, enable_text: false }})```
166
+
167
+ #### open_tracking (object)
168
+ Allows you to track whether the email was opened or not, but including a single pixel image in the body of the content. When the pixel is loaded, we can log that the email was opened.
169
+
170
+ ##### enable (boolean)
171
+ Indicates if this setting is enabled.
172
+
173
+ ##### substitution_tag (string)
174
+ Allows you to specify a substitution tag that you can insert in the body of your email at a location that you desire. This tag will be replaced by the open tracking pixel.
175
+
176
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', tracking_settings:{ enable: true, substitution_tag: 'Optional tag to replace with the open image in the body of the message' }})```
177
+
178
+ #### subscription_tracking (object)
179
+ Allows you to insert a subscription management link at the bottom of the text and html bodies of your email. If you would like to specify the location of the link within your email, you may use the substitution_tag.
180
+
181
+ ##### enable (boolean)
182
+ Indicates if this setting is enabled.
183
+
184
+ ##### text (string)
185
+ Text to be appended to the email, with the subscription tracking link. You may control where the link is by using the tag <% %>
186
+
187
+ ##### html (string)
188
+ HTML to be appended to the email, with the subscription tracking link. You may control where the link is by using the tag <% %>
189
+
190
+ ##### substitution_tag (string)
191
+ A tag that will be replaced with the unsubscribe URL. for example: [unsubscribe_url]. If this parameter is used, it will override both the text and html parameters. The URL of the link will be placed at the substitution tag’s location, with no additional formatting.
192
+
193
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', tracking_settings:{ enable: true, text: 'text to insert into the text/plain portion of the message', html: 'html to insert into the text/html portion of the message', substitution_tag: 'Optional tag to replace with the open image in the body of the message' }})```
194
+
195
+ #### ganalytics (object)
196
+ Allows you to enable tracking provided by Google Analytics.
197
+
198
+ ##### enable (boolean)
199
+ Indicates if this setting is enabled.
200
+
201
+ ##### utm_source (string)
202
+ Name of the referrer source. (e.g. Google, SomeDomain.com, or Marketing Email)
203
+
204
+ ##### utm_medium (string)
205
+ Name of the marketing medium. (e.g. Email)
206
+
207
+ ##### utm_term (string)
208
+ Used to identify any paid keywords.
209
+
210
+ ##### utm_content (string)
211
+ Used to differentiate your campaign from advertisements.
212
+
213
+ ##### utm_campaign (string)
214
+ The name of the campaign.
215
+
216
+ ```mail(to: 'example@email.com', subject: 'email subject', body: 'email body', tracking_settings:{ enable: true, utm_source: 'some source', utm_medium: 'some medium', utm_term: 'some term', utm_content: 'some content', utm_campaign: 'some campaign' }})```
217
+
218
+ ### Unsubscribe Links
92
219
 
93
- ## Contributing
220
+ Sendgrid unfortunately uses <% %> for their default substitution syntax, which makes it incompatible with Rails templates. Their proposed solution is to use Personalization Substitutions with the v3 Mail Send Endpoint. This gem makes that modification to make the following Rails friendly unsubscribe urls.
94
221
 
95
- 1. Fork it ( https://github.com/[my-github-username]/sendgrid-actionmailer/fork )
96
- 2. Create your feature branch (`git checkout -b my-new-feature`)
97
- 3. Commit your changes (`git commit -am 'Add some feature'`)
98
- 4. Push to the branch (`git push origin my-new-feature`)
99
- 5. Create a new Pull Request
222
+ * `<a href="%asm_group_unsubscribe_raw_url%">Unsubscribe</a>`
223
+ * `<a href="%asm_global_unsubscribe_raw_url%">Unsubscribe from List</a>`
224
+ * `<a href="%asm_preferences_raw_url%">Manage Email Preferences</a>`
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "mail", "2.7.0"
6
+
7
+ gemspec :path => "../"
@@ -1,136 +1,232 @@
1
1
  require 'sendgrid_actionmailer/version'
2
2
  require 'sendgrid_actionmailer/railtie' if defined? Rails
3
-
4
- require 'fileutils'
5
- require 'tmpdir'
6
-
7
3
  require 'sendgrid-ruby'
8
4
 
9
5
  module SendGridActionMailer
10
6
  class DeliveryMethod
11
- attr_reader :client
7
+ # TODO: use custom class to customer excpetion payload
8
+ SendgridDeliveryError = Class.new(StandardError)
12
9
 
13
- def initialize(params)
14
- @client = SendGrid::Client.new do |c|
15
- c.api_user = params[:api_user]
16
- c.api_key = params[:api_key]
17
- end
10
+ include SendGrid
11
+
12
+ DEFAULTS = {
13
+ raise_delivery_errors: false
14
+ }.freeze
15
+
16
+ attr_accessor :settings, :api_key
17
+
18
+ def initialize(**params)
19
+ self.settings = DEFAULTS.merge(params)
18
20
  end
19
21
 
20
22
  def deliver!(mail)
21
- attachment_temp_dirs = []
22
- from = mail[:from].addrs.first
23
-
24
- email = SendGrid::Mail.new do |m|
25
- m.to = mail[:to].addresses
26
- m.cc = mail[:cc].addresses if mail[:cc]
27
- m.bcc = mail[:bcc].addresses if mail[:bcc]
28
- m.from = from.address
29
- m.from_name = from.display_name
30
- m.reply_to = mail[:reply_to].addresses.first if mail[:reply_to]
31
- m.date = mail[:date].to_s if mail[:date]
32
- m.subject = mail.subject
33
- end
34
-
35
- smtpapi = mail['X-SMTPAPI']
36
-
37
- # If multiple X-SMTPAPI headers are present on the message, then pick the
38
- # first one. This may happen when X-SMTPAPI is set with defaults at the
39
- # class-level (using defaults()), as well as inside an individual method
40
- # (using headers[]=). In this case, we'll defer to the more specific
41
- # header set in the individual method, which is the first header
42
- # (somewhat counter-intuitively:
43
- # https://github.com/rails/rails/issues/15912).
44
- if(smtpapi.kind_of?(Array))
45
- smtpapi = smtpapi.first
46
- end
47
-
48
- if smtpapi && smtpapi.value
49
- begin
50
- data = JSON.parse(smtpapi.value)
51
-
52
- if data['filters']
53
- email.smtpapi.set_filters(data['filters'])
54
- end
23
+ sendgrid_mail = Mail.new.tap do |m|
24
+ m.from = to_email(mail.from)
25
+ m.reply_to = to_email(mail.reply_to)
26
+ m.subject = mail.subject
27
+ # https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/personalizations.html
28
+ m.add_personalization(to_personalizations(mail))
29
+ end
55
30
 
56
- if data['category']
57
- email.smtpapi.set_categories(data['category'])
58
- end
31
+ add_api_key(sendgrid_mail, mail)
32
+ add_content(sendgrid_mail, mail)
33
+ add_send_options(sendgrid_mail, mail)
34
+ add_mail_settings(sendgrid_mail, mail)
35
+ add_tracking_settings(sendgrid_mail, mail)
59
36
 
60
- if data['send_at']
61
- email.smtpapi.set_send_at(data['send_at'])
62
- end
37
+ response = perform_send_request(sendgrid_mail)
63
38
 
64
- if data['send_each_at']
65
- email.smtpapi.set_send_each_at(data['send_each_at'])
66
- end
39
+ settings[:return_response] ? response : self
40
+ end
67
41
 
68
- if data['section']
69
- email.smtpapi.set_sections(data['section'])
70
- end
42
+ private
71
43
 
72
- if data['sub']
73
- email.smtpapi.set_substitutions(data['sub'])
74
- end
44
+ def client
45
+ @client = SendGrid::API.new(api_key: api_key).client
46
+ end
75
47
 
76
- if data['asm_group_id']
77
- email.smtpapi.set_asm_group(data['asm_group_id'])
78
- end
48
+ # type should be either :plain or :html
49
+ def to_content(type, value)
50
+ Content.new(type: "text/#{type}", value: value)
51
+ end
79
52
 
80
- if data['unique_args']
81
- email.smtpapi.set_unique_args(data['unique_args'])
82
- end
53
+ def to_email(input)
54
+ to_emails(input).first
55
+ end
83
56
 
84
- if data['ip_pool']
85
- email.smtpapi.set_ip_pool(data['ip_pool'])
86
- end
87
- rescue JSON::ParserError
88
- raise ArgumentError, "X-SMTPAPI is not JSON: #{smtpapi.value}"
57
+ def to_emails(input)
58
+ if input.is_a?(String)
59
+ [Email.new(email: input)]
60
+ elsif input.is_a?(::Mail::AddressContainer) && !input.instance_variable_get('@field').nil?
61
+ input.instance_variable_get('@field').addrs.map do |addr| # Mail::Address
62
+ Email.new(email: addr.address, name: addr.name)
63
+ end
64
+ elsif input.is_a?(::Mail::AddressContainer)
65
+ input.map do |addr|
66
+ Email.new(email: addr)
89
67
  end
68
+ elsif input.is_a?(::Mail::StructuredField)
69
+ [Email.new(email: input.value)]
70
+ elsif input.nil?
71
+ []
72
+ else
73
+ puts "unknown type #{input.class.name}"
74
+ end
75
+ end
76
+
77
+ def to_personalizations(mail)
78
+ Personalization.new.tap do |p|
79
+ to_emails(mail.to).each { |to| p.add_to(to) }
80
+ to_emails(mail.cc).each { |cc| p.add_cc(cc) }
81
+ to_emails(mail.bcc).each { |bcc| p.add_bcc(bcc) }
82
+ p.add_substitution(Substitution.new(key: "%asm_group_unsubscribe_raw_url%", value: "<%asm_group_unsubscribe_raw_url%>"))
83
+ p.add_substitution(Substitution.new(key: "%asm_global_unsubscribe_raw_url%", value: "<%asm_global_unsubscribe_raw_url%>"))
84
+ p.add_substitution(Substitution.new(key: "%asm_preferences_raw_url%", value: "<%asm_preferences_raw_url%>"))
85
+ end
86
+ end
87
+
88
+ def to_attachment(part)
89
+ Attachment.new.tap do |a|
90
+ a.content = Base64.strict_encode64(part.body.decoded)
91
+ a.type = part.mime_type
92
+ a.filename = part.filename
93
+
94
+ disposition = get_disposition(part)
95
+ a.disposition = disposition unless disposition.nil?
96
+
97
+ has_content_id = part.header && part.has_content_id?
98
+ a.content_id = part.header['content_id'].value if has_content_id
90
99
  end
100
+ end
101
+
102
+ def get_disposition(message)
103
+ return if message.header.nil?
104
+ content_disp = message.header[:content_disposition]
105
+ return unless content_disp.respond_to?(:disposition_type)
106
+ content_disp.disposition_type
107
+ end
91
108
 
92
- # TODO: This is pretty ugly
109
+ def add_api_key(sendgrid_mail, mail)
110
+ self.api_key = settings.fetch(:api_key)
111
+ if mail['delivery-method-options'] && mail['delivery-method-options'].value.include?('api_key')
112
+ self.api_key = JSON.parse(mail['delivery-method-options'].value.gsub('=>', ':'))['api_key']
113
+ end
114
+ end
115
+
116
+ def add_content(sendgrid_mail, mail)
93
117
  case mail.mime_type
94
118
  when 'text/plain'
95
- # Text
96
- email.text = mail.body.decoded
119
+ sendgrid_mail.add_content(to_content(:plain, mail.body.decoded))
97
120
  when 'text/html'
98
- # HTML
99
- email.html = mail.body.decoded
121
+ sendgrid_mail.add_content(to_content(:html, mail.body.decoded))
100
122
  when 'multipart/alternative', 'multipart/mixed', 'multipart/related'
101
- email.html = mail.html_part.decoded if mail.html_part
102
- email.text = mail.text_part.decoded if mail.text_part
103
-
104
- mail.attachments.each do |a|
105
- # Write the attachment into a temporary location, since sendgrid-ruby
106
- # expects to deal with files.
107
- #
108
- # We write to a temporary directory (instead of a tempfile) and then
109
- # use the original filename inside there, since sendgrid-ruby's
110
- # add_content method pulls the filename from the path (so tempfiles
111
- # would lead to random filenames).
112
- temp_dir = Dir.mktmpdir('sendgrid-actionmailer')
113
- attachment_temp_dirs << temp_dir
114
- temp_path = File.join(temp_dir, a.filename)
115
- File.open(temp_path, 'wb') do |file|
116
- file.write(a.read)
123
+ sendgrid_mail.add_content(to_content(:plain, mail.text_part.decoded)) if mail.text_part
124
+ sendgrid_mail.add_content(to_content(:html, mail.html_part.decoded)) if mail.html_part
125
+
126
+ mail.attachments.each do |part|
127
+ sendgrid_mail.add_attachment(to_attachment(part))
128
+ end
129
+ end
130
+ end
131
+
132
+ def json_parse(text, symbolize=true)
133
+ JSON.parse(text.gsub(/:*\"*([\%a-zA-Z0-9_-]*)\"*(( *)=>\ *)/) { "\"#{$1}\":" }, symbolize_names: symbolize)
134
+ end
135
+
136
+ def add_send_options(sendgrid_mail, mail)
137
+ if mail['template_id']
138
+ sendgrid_mail.template_id = mail['template_id'].to_s
139
+ end
140
+ if mail['sections']
141
+ json_parse(mail['sections'].value, false).each do |key, value|
142
+ sendgrid_mail.add_section(Section.new(key: key, value: value))
143
+ end
144
+ end
145
+ if mail['headers']
146
+ json_parse(mail['headers'].value, false).each do |key, value|
147
+ sendgrid_mail.add_header(Header.new(key: key, value: value))
148
+ end
149
+ end
150
+ if mail['categories']
151
+ mail['categories'].value.split(",").each do |value|
152
+ sendgrid_mail.add_category(Category.new(name: value.strip))
153
+ end
154
+ end
155
+ if mail['custom_args']
156
+ json_parse(mail['custom_args'].value, false).each do |key, value|
157
+ sendgrid_mail.add_custom_arg(CustomArg.new(key: key, value: value))
158
+ end
159
+ end
160
+ if mail['send_at'] && mail['batch_id']
161
+ sendgrid_mail.send_at = mail['send_at'].value.to_i
162
+ sendgrid_mail.batch_id= mail['batch_id'].to_s
163
+ end
164
+ if mail['asm']
165
+ asm = json_parse(mail['asm'].value)
166
+ asm = asm.delete_if { |key, value| !key.to_s.match(/(group_id)|(groups_to_display)/) }
167
+ if asm[:group_id]
168
+ sendgrid_mail.asm = ASM.new(asm)
169
+ end
170
+ end
171
+ if mail['ip_pool_name']
172
+ sendgrid_mail.ip_pool_name = mail['ip_pool_name'].to_s
173
+ end
174
+ end
175
+
176
+ def add_mail_settings(sendgrid_mail, mail)
177
+ if mail['mail_settings']
178
+ settings = json_parse(mail['mail_settings'].value)
179
+ sendgrid_mail.mail_settings = MailSettings.new.tap do |m|
180
+ if settings[:bcc]
181
+ m.bcc = BccSettings.new(settings[:bcc])
182
+ end
183
+ if settings[:bypass_list_management]
184
+ m.bypass_list_management = BypassListManagement.new(settings[:bypass_list_management])
185
+ end
186
+ if settings[:footer]
187
+ m.footer = Footer.new(settings[:footer])
117
188
  end
189
+ if settings[:sandbox_mode]
190
+ m.sandbox_mode = SandBoxMode.new(settings[:sandbox_mode])
191
+ end
192
+ if settings[:spam_check]
193
+ m.spam_check = SpamCheck.new(settings[:spam_check])
194
+ end
195
+ end
196
+ end
197
+ end
118
198
 
119
- if(mail.mime_type == 'multipart/related' && a.header[:content_id])
120
- email.add_content(temp_path, a.header[:content_id].field.content_id)
121
- else
122
- email.add_attachment(temp_path, a.filename)
199
+ def add_tracking_settings(sendgrid_mail, mail)
200
+ if mail['tracking_settings']
201
+ settings = json_parse(mail['tracking_settings'].value)
202
+ sendgrid_mail.tracking_settings = TrackingSettings.new.tap do |t|
203
+ if settings[:click_tracking]
204
+ t.click_tracking = ClickTracking.new(settings[:click_tracking])
205
+ end
206
+ if settings[:open_tracking]
207
+ t.open_tracking = OpenTracking.new(settings[:open_tracking])
208
+ end
209
+ if settings[:subscription_tracking]
210
+ t.subscription_tracking = SubscriptionTracking.new(settings[:subscription_tracking])
211
+ end
212
+ if settings[:ganalytics]
213
+ t.ganalytics = Ganalytics.new(settings[:ganalytics])
123
214
  end
124
215
  end
125
216
  end
217
+ end
218
+
219
+ def perform_send_request(email)
220
+ result = client.mail._('send').post(request_body: email.to_json) # ლ(ಠ益ಠლ) that API
126
221
 
127
- client.send(email)
128
- ensure
129
- # Close and delete the attachment tempfiles after the e-mail has been
130
- # sent.
131
- attachment_temp_dirs.each do |dir|
132
- FileUtils.remove_entry_secure(dir)
222
+ if result.status_code && result.status_code.start_with?('4')
223
+ message = JSON.parse(result.body).fetch('errors').pop.fetch('message')
224
+ full_message = "Sendgrid delivery failed with #{result.status_code} #{message}"
225
+
226
+ settings[:raise_delivery_errors] ? raise(SendgridDeliveryError, full_message) : warn(full_message)
133
227
  end
228
+
229
+ result
134
230
  end
135
231
  end
136
232
  end