send_grid_mailer 1.2.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +102 -0
  3. data/.circleci/setup-rubygems.sh +3 -0
  4. data/.rubocop.yml +19 -579
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +10 -0
  7. data/README.md +33 -1
  8. data/lib/send_grid_mailer/definition.rb +32 -14
  9. data/lib/send_grid_mailer/dev_deliverer.rb +11 -2
  10. data/lib/send_grid_mailer/logger.rb +6 -1
  11. data/lib/send_grid_mailer/mailer_base_ext.rb +2 -0
  12. data/lib/send_grid_mailer/version.rb +1 -1
  13. data/send_grid_mailer.gemspec +12 -7
  14. data/spec/dummy/Rakefile +1 -1
  15. data/spec/dummy/app/assets/config/manifest.js +3 -0
  16. data/spec/dummy/app/assets/stylesheets/application.css +3 -3
  17. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  18. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  19. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  20. data/spec/dummy/app/{assets/javascripts → javascript/packs}/application.js +3 -1
  21. data/spec/dummy/app/jobs/application_job.rb +7 -0
  22. data/spec/dummy/app/mailers/application_mailer.rb +1 -1
  23. data/spec/dummy/app/mailers/test_mailer.rb +6 -0
  24. data/spec/dummy/app/models/application_record.rb +3 -0
  25. data/spec/dummy/app/views/layouts/application.html.erb +10 -9
  26. data/spec/dummy/bin/rails +3 -3
  27. data/spec/dummy/bin/rake +2 -2
  28. data/spec/dummy/bin/setup +18 -14
  29. data/spec/dummy/config.ru +3 -1
  30. data/spec/dummy/config/application.rb +12 -22
  31. data/spec/dummy/config/boot.rb +3 -3
  32. data/spec/dummy/config/cable.yml +10 -0
  33. data/spec/dummy/config/database.yml +2 -2
  34. data/spec/dummy/config/environment.rb +1 -1
  35. data/spec/dummy/config/environments/development.rb +48 -18
  36. data/spec/dummy/config/environments/production.rb +63 -22
  37. data/spec/dummy/config/environments/test.rb +29 -12
  38. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  39. data/spec/dummy/config/initializers/assets.rb +4 -3
  40. data/spec/dummy/config/initializers/backtrace_silencers.rb +4 -3
  41. data/spec/dummy/config/initializers/content_security_policy.rb +28 -0
  42. data/spec/dummy/config/initializers/cookies_serializer.rb +2 -0
  43. data/spec/dummy/config/initializers/filter_parameter_logging.rb +3 -1
  44. data/spec/dummy/config/initializers/permissions_policy.rb +11 -0
  45. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -2
  46. data/spec/dummy/config/locales/en.yml +11 -1
  47. data/spec/dummy/config/puma.rb +43 -0
  48. data/spec/dummy/config/routes.rb +1 -54
  49. data/spec/dummy/config/storage.yml +34 -0
  50. data/spec/dummy/public/404.html +6 -6
  51. data/spec/dummy/public/422.html +6 -6
  52. data/spec/dummy/public/500.html +6 -6
  53. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  54. data/spec/dummy/public/apple-touch-icon.png +0 -0
  55. data/spec/dummy/spec/lib/send_grid_mailer/definition_spec.rb +52 -23
  56. data/spec/dummy/spec/mailers/test_mailer_spec.rb +84 -46
  57. data/spec/rails_helper.rb +3 -5
  58. metadata +142 -71
  59. data/.hound.yml +0 -4
  60. data/.travis.yml +0 -15
  61. data/spec/dummy/bin/bundle +0 -3
  62. data/spec/dummy/config/initializers/session_store.rb +0 -3
  63. data/spec/dummy/config/secrets.yml +0 -22
  64. data/spec/dummy/db/schema.rb +0 -16
  65. data/spec/dummy/spec/support/test_helpers.rb +0 -5
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.3
1
+ 2.7
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
+ ### v2.0.0
6
+
7
+ ##### Changed
8
+
9
+ * Replace travis with circleci.
10
+
11
+ ##### Removed
12
+
13
+ * Support for Ruby 2.5
14
+
5
15
  ### v1.2.1
6
16
 
7
17
  ##### Fixed
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SendGrid Mailer
2
2
  [![Gem Version](https://badge.fury.io/rb/send_grid_mailer.svg)](https://badge.fury.io/rb/send_grid_mailer)
3
- [![Build Status](https://travis-ci.org/platanus/send_grid_mailer.svg?branch=master)](https://travis-ci.org/platanus/send_grid_mailer)
3
+ [![CircleCI](https://circleci.com/gh/platanus/send_grid_mailer.svg?style=shield)](https://app.circleci.com/pipelines/github/platanus/send_grid_mailer)
4
4
  [![Coverage Status](https://coveralls.io/repos/github/platanus/send_grid_mailer/badge.svg)](https://coveralls.io/github/platanus/send_grid_mailer)
5
5
 
6
6
  Is an Action Mailer adapter for using SendGrid in a Rails application and
@@ -169,6 +169,28 @@ class TestMailer < ApplicationMailer
169
169
  end
170
170
  ```
171
171
 
172
+ #### Set Dynamic Template Data
173
+
174
+ ```ruby
175
+ class TestMailer < ApplicationMailer
176
+ def my_email
177
+ dynamic_template_data({ key1: "value1", key2: "value2" })
178
+ mail
179
+ end
180
+ end
181
+ ```
182
+
183
+ #### Add Category
184
+
185
+ ```ruby
186
+ class TestMailer < ApplicationMailer
187
+ def my_email
188
+ add_category("value")
189
+ mail
190
+ end
191
+ end
192
+ ```
193
+
172
194
  > Remember: you need to specify al least: `body`, `template_id` or a Rails template.
173
195
 
174
196
  ## Recipient Interceptor
@@ -205,6 +227,16 @@ bundle exec guard
205
227
 
206
228
  You need to put **all your tests** in the `/send_grid_mailer/spec/dummy/spec/` directory.
207
229
 
230
+ ## Publishing
231
+
232
+ On master/main branch...
233
+
234
+ 1. Change `VERSION` in `lib/send_grid_mailer/version.rb`.
235
+ 2. Change `Unreleased` title to current version in `CHANGELOG.md`.
236
+ 3. Commit new release. For example: `Releasing v0.1.0`.
237
+ 4. Create tag. For example: `git tag v0.1.0`.
238
+ 5. Push tag. For example: `git push origin v0.1.0`.
239
+
208
240
  ## Contributing
209
241
 
210
242
  1. Fork it
@@ -2,28 +2,36 @@ module SendGridMailer
2
2
  class Definition
3
3
  METHODS = [
4
4
  :substitute,
5
+ :dynamic_template_data,
5
6
  :set_template_id,
6
7
  :set_sender,
7
8
  :set_recipients,
8
9
  :set_subject,
9
10
  :set_content,
10
11
  :add_attachment,
11
- :add_header
12
+ :add_header,
13
+ :add_category
12
14
  ]
13
15
 
14
16
  def substitute(key, value, default = "")
15
- personalization.substitutions = SendGrid::Substitution.new(
16
- key: key, value: value.to_s || default
17
+ personalization.add_substitution(
18
+ SendGrid::Substitution.new(key: key, value: value.to_s || default)
17
19
  )
18
20
  end
19
21
 
22
+ def dynamic_template_data(object)
23
+ personalization.add_dynamic_template_data(object)
24
+ end
25
+
20
26
  def set_template_id(value)
21
27
  return unless value
28
+
22
29
  mail.template_id = value
23
30
  end
24
31
 
25
32
  def set_sender(email)
26
33
  return unless email
34
+
27
35
  matched_format = email.match(/<(.+)>/)
28
36
  if matched_format
29
37
  address = matched_format[1]
@@ -37,19 +45,22 @@ module SendGridMailer
37
45
  def set_recipients(mode, *emails)
38
46
  emails.flatten.each do |email|
39
47
  next unless email
40
- personalization.send("#{mode}=", SendGrid::Email.new(email: email))
48
+
49
+ personalization.send("add_#{mode}", SendGrid::Email.new(email: email))
41
50
  end
42
51
  end
43
52
 
44
53
  def set_subject(value)
45
54
  return unless value
55
+
46
56
  personalization.subject = value
47
57
  end
48
58
 
49
59
  def set_content(value, type = nil)
50
60
  return unless value
51
- type = "text/plain" unless type
52
- mail.contents = SendGrid::Content.new(type: type, value: value)
61
+
62
+ type ||= "text/plain"
63
+ mail.add_content(SendGrid::Content.new(type: type, value: value))
53
64
  end
54
65
 
55
66
  def add_attachment(file, name, type, disposition = "inline", content_id = nil)
@@ -59,16 +70,23 @@ module SendGridMailer
59
70
  attachment.filename = name
60
71
  attachment.disposition = disposition
61
72
  attachment.content_id = content_id
62
- mail.attachments = attachment
73
+ mail.add_attachment(attachment)
63
74
  end
64
75
 
65
76
  def add_header(key, value)
66
77
  return if !key || !value
67
- personalization.headers = SendGrid::Header.new(key: key, value: value)
78
+
79
+ personalization.add_header(SendGrid::Header.new(key: key, value: value))
80
+ end
81
+
82
+ def add_category(value)
83
+ return unless value
84
+
85
+ mail.add_category(SendGrid::Category.new(name: value))
68
86
  end
69
87
 
70
88
  def to_json
71
- mail.personalizations = personalization if personalization?
89
+ mail.add_personalization(personalization) if personalization?
72
90
  mail.to_json
73
91
  end
74
92
 
@@ -77,7 +95,7 @@ module SendGridMailer
77
95
  end
78
96
 
79
97
  def clean_recipients(mode)
80
- personalization.instance_variable_set("@#{mode}s", nil)
98
+ personalization.instance_variable_set("@#{mode}s", [])
81
99
  end
82
100
 
83
101
  def personalization
@@ -86,12 +104,12 @@ module SendGridMailer
86
104
 
87
105
  def personalization?; !personalization.to_json.empty? end
88
106
 
89
- def content?; !mail.contents.blank? end
107
+ def content?; mail.contents.present? end
90
108
 
91
- def sender?; !mail.from.blank? end
109
+ def sender?; mail.from.present? end
92
110
 
93
- def subject?; !personalization.subject.blank? end
111
+ def subject?; personalization.subject.present? end
94
112
 
95
- def template_id?; !mail.template_id.blank? end
113
+ def template_id?; mail.template_id.present? end
96
114
  end
97
115
  end
@@ -3,6 +3,7 @@ module SendGridMailer
3
3
  include InterceptorsHandler
4
4
  include Logger
5
5
  require "letter_opener"
6
+ require "handlebars"
6
7
 
7
8
  def deliver!(sg_definition)
8
9
  @sg_definition = sg_definition
@@ -24,17 +25,25 @@ module SendGridMailer
24
25
  end
25
26
 
26
27
  def letter_opener_delivery_method
27
- @letter_opener_delivery_method ||= LetterOpener::DeliveryMethod.new(location: '/tmp/mails')
28
+ @letter_opener_delivery_method ||= LetterOpener::DeliveryMethod.new(location: dev_emails_location)
29
+ end
30
+
31
+ def dev_emails_location
32
+ Rails.application.config.action_mailer.sendgrid_dev_settings[:emails_location] || "/tmp/mails"
33
+ rescue
34
+ "/tmp/mails"
28
35
  end
29
36
 
30
37
  def parsed_template
31
38
  template_response = sg_api.get_template(@sg_definition)
32
39
  template_versions = JSON.parse(template_response.body)["versions"]
33
- return unless template_versions.present?
40
+ return if template_versions.blank?
34
41
 
35
42
  template_active_version = template_versions.find { |version| version["active"] == 1 }
36
43
  template_content = template_active_version["html_content"]
37
44
  @sg_definition.personalization.substitutions.each { |k, v| template_content.gsub!(k, v) }
45
+ template = Handlebars::Context.new.compile(template_content)
46
+ template_content = template.call(@sg_definition.personalization.dynamic_template_data)
38
47
  template_content
39
48
  end
40
49
 
@@ -40,18 +40,20 @@ module SendGridMailer
40
40
  def build_definition_message(data)
41
41
  data = data.keys.map do |k|
42
42
  d = data[k].to_s
43
- "#{k}: #{(d.blank? ? '-' : d)}"
43
+ "#{k}: #{d.presence || '-'}"
44
44
  end.join("\n")
45
45
  end
46
46
 
47
47
  def log_email(email)
48
48
  return if email.blank?
49
+
49
50
  email["email"]
50
51
  end
51
52
 
52
53
  def log_emails(personalization, origin)
53
54
  emails = personalization.send(origin)
54
55
  return if emails.blank?
56
+
55
57
  emails.map do |email|
56
58
  log_email(email)
57
59
  end.join(", ")
@@ -59,6 +61,7 @@ module SendGridMailer
59
61
 
60
62
  def log_attachments(mail)
61
63
  return if mail.attachments.blank?
64
+
62
65
  mail.attachments.map do |f|
63
66
  "\n\t#{f['filename']}"
64
67
  end.join("")
@@ -66,6 +69,7 @@ module SendGridMailer
66
69
 
67
70
  def log_contents(mail)
68
71
  return if mail.contents.blank?
72
+
69
73
  mail.contents.map do |content|
70
74
  "\n\ttype: #{content['type']}\n\tvalue: #{content['value']}"
71
75
  end.join("")
@@ -73,6 +77,7 @@ module SendGridMailer
73
77
 
74
78
  def log_pairs(hash)
75
79
  return if hash.blank?
80
+
76
81
  hash.keys.map do |k|
77
82
  "\n\t#{k} => #{hash[k]}"
78
83
  end.join("")
@@ -59,8 +59,10 @@ module ActionMailer
59
59
  def set_body(params)
60
60
  set_template_id(params[:template_id])
61
61
  return if sg_definition.template_id?
62
+
62
63
  set_content(params[:body], params[:content_type])
63
64
  return if sg_definition.content?
65
+
64
66
  set_body_from_tpl(params)
65
67
  end
66
68
 
@@ -1,3 +1,3 @@
1
1
  module SendGridMailer
2
- VERSION = "1.2.1"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -19,14 +19,19 @@ Gem::Specification.new do |s|
19
19
  s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  s.test_files = Dir["spec/**/*"]
21
21
 
22
- s.add_dependency "rails", ">= 4.2.0"
23
- s.add_dependency "sendgrid-ruby", "~> 4.0", ">= 4.0.4"
22
+ s.add_dependency "handlebars", "~> 0.8.0"
24
23
  s.add_dependency "letter_opener", "~> 1.7.0"
24
+ s.add_dependency "rails", ">= 4.2.0"
25
+ s.add_dependency "sendgrid-ruby", "~> 5", ">= 5.3.0"
26
+
27
+ s.add_development_dependency "coveralls"
28
+ s.add_development_dependency "factory_bot_rails"
29
+ s.add_development_dependency "guard-rspec", "~> 4.7"
25
30
  s.add_development_dependency "pry"
26
31
  s.add_development_dependency "pry-rails"
27
- s.add_development_dependency "sqlite3", "~> 1.3.13"
28
- s.add_development_dependency "rspec-rails", "~> 3.4.0"
29
- s.add_development_dependency "guard-rspec", "~> 4.7"
30
- s.add_development_dependency "factory_bot_rails"
31
- s.add_development_dependency "coveralls"
32
+ s.add_development_dependency "rspec-rails", "~> 3.5.0"
33
+ s.add_development_dependency "rspec_junit_formatter"
34
+ s.add_development_dependency "rubocop", "0.65.0"
35
+ s.add_development_dependency "rubocop-rspec"
36
+ s.add_development_dependency "sqlite3", "~> 1.4"
32
37
  end
data/spec/dummy/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  # Add your own tasks in files placed in lib/tasks ending in .rake,
2
2
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
3
 
4
- require File.expand_path('../config/application', __FILE__)
4
+ require_relative "config/application"
5
5
 
6
6
  Rails.application.load_tasks
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../stylesheets .css
3
+ //= link send_grid_mailer_manifest.js
@@ -6,9 +6,9 @@
6
6
  * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
7
  *
8
8
  * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
- * compiled file so the styles you add here take precedence over styles defined in any styles
10
- * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
- * file per style scope.
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
12
  *
13
13
  *= require_tree .
14
14
  *= require_self
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -1,5 +1,2 @@
1
1
  class ApplicationController < ActionController::Base
2
- # Prevent CSRF attacks by raising an exception.
3
- # For APIs, you may want to use :null_session instead.
4
- protect_from_forgery with: :exception
5
2
  end
@@ -5,9 +5,11 @@
5
5
  // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
6
  //
7
7
  // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
- // compiled file.
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
9
  //
10
10
  // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
11
  // about supported directives.
12
12
  //
13
+ //= require rails-ujs
14
+ //= require activestorage
13
15
  //= require_tree .
@@ -0,0 +1,7 @@
1
+ class ApplicationJob < ActiveJob::Base
2
+ # Automatically retry jobs that encountered a deadlock
3
+ # retry_on ActiveRecord::Deadlocked
4
+
5
+ # Most jobs are safe to ignore if the underlying records are no longer available
6
+ # discard_on ActiveJob::DeserializationError
7
+ end
@@ -1,4 +1,4 @@
1
1
  class ApplicationMailer < ActionMailer::Base
2
- default from: "from@example.com"
2
+ default from: 'from@example.com'
3
3
  layout 'mailer'
4
4
  end
@@ -84,4 +84,10 @@ class TestMailer < ApplicationMailer
84
84
  substitute "%key%", value
85
85
  mail(to: "r1@platan.us", body: "X")
86
86
  end
87
+
88
+ def dynamic_template_email(value)
89
+ set_template_id("XXX")
90
+ dynamic_template_data(key: value)
91
+ mail(to: "r1@platan.us")
92
+ end
87
93
  end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
@@ -1,14 +1,15 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
- <head>
4
- <title>Dummy</title>
5
- <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6
- <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7
- <%= csrf_meta_tags %>
8
- </head>
9
- <body>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
10
8
 
11
- <%= yield %>
9
+ <%= stylesheet_link_tag 'application', media: 'all' %>
10
+ </head>
12
11
 
13
- </body>
12
+ <body>
13
+ <%= yield %>
14
+ </body>
14
15
  </html>
data/spec/dummy/bin/rails CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- APP_PATH = File.expand_path('../../config/application', __FILE__)
3
- require_relative '../config/boot'
4
- require 'rails/commands'
2
+ APP_PATH = File.expand_path('../config/application', __dir__)
3
+ require_relative "../config/boot"
4
+ require "rails/commands"