sendgrid_notification 0.1.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +92 -0
- data/Rakefile +36 -0
- data/app/assets/config/sendgrid_notification_manifest.js +2 -0
- data/app/assets/javascripts/sendgrid_notification/application.js +13 -0
- data/app/assets/stylesheets/sendgrid_notification/application.css +15 -0
- data/app/controllers/sendgrid_notification/application_controller.rb +5 -0
- data/app/helpers/sendgrid_notification/application_helper.rb +4 -0
- data/app/jobs/sendgrid_notification/application_job.rb +4 -0
- data/app/jobs/sendgrid_notification/sendmail_job.rb +11 -0
- data/app/mailers/sendgrid_notification/application_mailer.rb +6 -0
- data/app/models/sendgrid_notification/application_record.rb +5 -0
- data/app/models/sendgrid_notification/mail_history.rb +15 -0
- data/app/models/sendgrid_notification/mail_recordable.rb +17 -0
- data/app/models/sendgrid_notification/notification_mail.rb +39 -0
- data/app/models/sendgrid_notification/null_mailer.rb +29 -0
- data/app/models/sendgrid_notification/sendgrid_client.rb +88 -0
- data/app/models/sendgrid_notification/sendgrid_mailer.rb +45 -0
- data/app/models/sendgrid_notification/sendgrid_status.rb +89 -0
- data/app/models/sendgrid_notification/sendgrid_status_update_history.rb +16 -0
- data/app/models/sendgrid_notification/template_parameters_validator.rb +12 -0
- data/app/views/layouts/sendgrid_notification/application.html.erb +14 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20170208085706_create_notification_mails.rb +13 -0
- data/db/migrate/20170208113843_create_mail_histories.rb +13 -0
- data/db/migrate/20170217072256_create_sendgrid_status_update_histories.rb +12 -0
- data/lib/sendgrid_notification/engine.rb +19 -0
- data/lib/sendgrid_notification/version.rb +3 -0
- data/lib/sendgrid_notification.rb +4 -0
- data/lib/tasks/sendgrid_notification_tasks.rake +56 -0
- metadata +186 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 90775898ca7fc2946047128eedcdddce10254fdf
|
4
|
+
data.tar.gz: f1ac7c958212d54a465c8f22af4cda0dcd587e1f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 900f013823a5951052e7c113080d84b03a7381ddf61362fff59227543631c2a222e4e49d2db9f91bb21798368cf427679d5c15240284319cbd962d79b647ef29
|
7
|
+
data.tar.gz: 9b91afb7880024fc55f2edf5cdf65d0520441a5cba56af5733507b7de3b3e8c3673b58d77fd600a42bc3af6c503d0a0cf37c4a684d8c8157dbe64a6cc9694a30
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 HORII Keima
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# SendgridNotification
|
2
|
+
|
3
|
+
SendgridNotification is engine of Ruby on Rails, and
|
4
|
+
notification mail (e.g. account registration, logging in by new devise,
|
5
|
+
reminder, etc...) sender and utility, using SendGrid API.
|
6
|
+
|
7
|
+
This provides mail utility models, migrations, and rake tasks.
|
8
|
+
|
9
|
+
## Installation / Usage
|
10
|
+
|
11
|
+
First, add sendgird_notification in Gemfile
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'sendgrid_notification'
|
15
|
+
```
|
16
|
+
|
17
|
+
```sh
|
18
|
+
bundle install
|
19
|
+
```
|
20
|
+
|
21
|
+
Then, generate migration files and migrate
|
22
|
+
|
23
|
+
```sh
|
24
|
+
bin/rails sendgrid_notification_engine:install:migrations
|
25
|
+
bin/rails db:migrate
|
26
|
+
```
|
27
|
+
|
28
|
+
Generate and edit controllers for NotificationMail CRUD
|
29
|
+
|
30
|
+
```
|
31
|
+
...
|
32
|
+
```
|
33
|
+
|
34
|
+
Create NotificationMail record. key = 'example'
|
35
|
+
|
36
|
+
|
37
|
+
```
|
38
|
+
...
|
39
|
+
```
|
40
|
+
|
41
|
+
And send the mail
|
42
|
+
|
43
|
+
```
|
44
|
+
...
|
45
|
+
```
|
46
|
+
|
47
|
+
Oops. It lacks SendGrid API configuration. Get API key from sendgrid.com and set it ENV['SENDGRID_API_KEY']
|
48
|
+
|
49
|
+
|
50
|
+
```
|
51
|
+
...
|
52
|
+
```
|
53
|
+
|
54
|
+
### Make subclasses for each notification_mail key
|
55
|
+
|
56
|
+
```
|
57
|
+
...
|
58
|
+
```
|
59
|
+
|
60
|
+
### Validate mail template has right parameter name
|
61
|
+
|
62
|
+
```
|
63
|
+
...
|
64
|
+
```
|
65
|
+
|
66
|
+
## Configuration
|
67
|
+
|
68
|
+
| Name | Description | Default Value |
|
69
|
+
|------|-------------|---------------|
|
70
|
+
| config.sendgrid_notification.api_key | SendGrid API Key | `ENV['SENDGRID_API_KEY']` |
|
71
|
+
| config.sendgrid_notification.mail_from | FROM address of notification mail | `ENV['SENDGRID_MAIL_FROM']` |
|
72
|
+
| config.sendgrid_notification.mail_from_name | FROM name of notification mail | `ENV['SENDGRID_MAIL_FROM_NAME']` |
|
73
|
+
| config.sendgrid_notification.mailer | Mailer class name (by string). usually no need to change | `"SendgridNotification::SendgridMailer"` |
|
74
|
+
|
75
|
+
## Rake tasks
|
76
|
+
|
77
|
+
| Task | Description | ENV/Parameter |
|
78
|
+
|------|-------------|----------------|
|
79
|
+
| sendgrid_notification:send | Send mail | TO=[recipient email address] KEY=[mail type key] ... and mail parameters |
|
80
|
+
| sendgrid_notification:status:autoupdate | Update status from previous autoupdate task | |
|
81
|
+
| sendgrid_notification:status:retrieve | Only retrieve suppression statuses in start..end | start=[datetime] end=[datetime] |
|
82
|
+
| sendgrid_notification:status:update | Retrieve suppression status and update record | start=[datetime] end=[datetime] |
|
83
|
+
| sendgrid_notification:testmail:init | Create notification_mails test record. default key = "_test" |
|
84
|
+
| sendgrid_notification:testmail:send | Send testmail | TO=[recipient email address] [body=body] |
|
85
|
+
|
86
|
+
## Contributing
|
87
|
+
|
88
|
+
Contribution directions go here.
|
89
|
+
|
90
|
+
## License
|
91
|
+
|
92
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'SendgridNotification'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
require 'bundler/gem_tasks'
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'test'
|
31
|
+
t.pattern = 'test/**/*_test.rb'
|
32
|
+
t.verbose = false
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
task default: :test
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
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. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
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 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
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module SendgridNotification
|
2
|
+
class SendmailJob < ActiveJob::Base
|
3
|
+
queue_as :sendmail
|
4
|
+
|
5
|
+
MailerClass = Rails.application.config.sendgrid_notification.mailer.constantize
|
6
|
+
|
7
|
+
def perform(to, notification_mail, params)
|
8
|
+
MailerClass.new.sendmail(to, notification_mail, params)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SendgridNotification
|
2
|
+
class MailHistory < ActiveRecord::Base
|
3
|
+
belongs_to :notification_mail, primary_key: :key, foreign_key: :key, required: false
|
4
|
+
|
5
|
+
with_options presence: true do
|
6
|
+
validates :key
|
7
|
+
validates :to
|
8
|
+
validates :sent_at
|
9
|
+
end
|
10
|
+
|
11
|
+
def error?
|
12
|
+
error_type?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# prepend me
|
2
|
+
module SendgridNotification
|
3
|
+
module MailRecordable
|
4
|
+
def sendmail(to, notification_mail, params = {})
|
5
|
+
result = super
|
6
|
+
|
7
|
+
m = MailHistory.create(
|
8
|
+
key: notification_mail.key,
|
9
|
+
to: to,
|
10
|
+
sent_at: Time.now,
|
11
|
+
)
|
12
|
+
Rails.logger.error m.errors.full_messages if m.invalid? # and ignore
|
13
|
+
|
14
|
+
result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SendgridNotification
|
2
|
+
class NotificationMail < ActiveRecord::Base
|
3
|
+
|
4
|
+
with_options presence: true do
|
5
|
+
validates :key, uniqueness: true
|
6
|
+
validates :subject
|
7
|
+
validates :content
|
8
|
+
end
|
9
|
+
|
10
|
+
class_attribute :variable_regexp
|
11
|
+
|
12
|
+
VARIABLE_REGEXP_DEFAULT = /\{\{\s*(\w+)\s*\}\}/
|
13
|
+
self.variable_regexp = VARIABLE_REGEXP_DEFAULT
|
14
|
+
|
15
|
+
|
16
|
+
def sendmail_later(to, params = {})
|
17
|
+
SendmailJob.perform_later(to, self, params)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias_method :sendmail, :sendmail_later
|
21
|
+
|
22
|
+
def sendmail_now(to, params = {})
|
23
|
+
SendmailJob.perform_now(to, self, params)
|
24
|
+
end
|
25
|
+
|
26
|
+
def apply(params)
|
27
|
+
unresolved = []
|
28
|
+
body = content.gsub(variable_regexp) { |_|
|
29
|
+
key = $1
|
30
|
+
params[key] || params[key.to_sym] || unresolved.push(key)
|
31
|
+
}
|
32
|
+
if unresolved.present?
|
33
|
+
errors.add(:content, :unresolved_template_parameters, variables: unresolved.join(","))
|
34
|
+
end
|
35
|
+
body
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'sendgrid-ruby'
|
2
|
+
|
3
|
+
module SendgridNotification
|
4
|
+
class NullMailer
|
5
|
+
prepend MailRecordable
|
6
|
+
|
7
|
+
Result = Struct.new(:from, :to, :subject, :body, :sent_at)
|
8
|
+
|
9
|
+
@@results = []
|
10
|
+
cattr_reader :results
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@from = Rails.application.config.sendgrid_notification.mail_from
|
14
|
+
end
|
15
|
+
|
16
|
+
def sendmail(to, notification_mail, params = {})
|
17
|
+
body = notification_mail.apply(params)
|
18
|
+
results << Result.new(@from, to, notification_mail.subject, body, Time.now)
|
19
|
+
end
|
20
|
+
|
21
|
+
def last_result
|
22
|
+
results.last
|
23
|
+
end
|
24
|
+
|
25
|
+
def last_result_success?
|
26
|
+
results.present?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'sendgrid-ruby'
|
2
|
+
|
3
|
+
# monkey patch
|
4
|
+
class SendGrid::Response
|
5
|
+
# about status code, see https://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html
|
6
|
+
def success?
|
7
|
+
status_code && status_code.to_i < 300
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module SendgridNotification
|
12
|
+
class SendgridClient
|
13
|
+
class Error < RuntimeError; end
|
14
|
+
|
15
|
+
class Response < SendGrid::Response
|
16
|
+
attr_reader :raw
|
17
|
+
|
18
|
+
def initialize(send_grid_response) # SendGrid::Response, has status_code, body, headers
|
19
|
+
@raw = send_grid_response
|
20
|
+
end
|
21
|
+
|
22
|
+
def status_code
|
23
|
+
raw.try(:status_code).try(:to_i)
|
24
|
+
end
|
25
|
+
|
26
|
+
def success?
|
27
|
+
status_code && status_code < 300
|
28
|
+
end
|
29
|
+
|
30
|
+
def body
|
31
|
+
raw.try(:body) ? JSON.parse(raw.body) : ''
|
32
|
+
end
|
33
|
+
|
34
|
+
delegate :headers, to: :raw
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :api_key, :api, :last_response
|
38
|
+
|
39
|
+
delegate :client, to: :api
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@api_key = Rails.application.config.sendgrid_notification.api_key
|
43
|
+
if api_key.blank?
|
44
|
+
raise Error, "no sendgrid api_key. set config.sendgrid_notification.api_key or " \
|
45
|
+
"SENDGRID_API_KEY environment variable."
|
46
|
+
end
|
47
|
+
@api = SendGrid::API.new(api_key: api_key)
|
48
|
+
@last_response = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# TODO: status_code が 500 系およびタイムアウトのときにリトライできるようにする
|
52
|
+
# POST /mail/send
|
53
|
+
def mail_send(from:, from_name:, to:, subject:, body:)
|
54
|
+
mail = build_mail(from, from_name, to, subject, body)
|
55
|
+
res = client.mail._('send').post(request_body: mail.to_json)
|
56
|
+
@last_response = Response.new(res)
|
57
|
+
end
|
58
|
+
|
59
|
+
SUPPRESSION_TYPES = %w(invalid_emails bounces blocks).freeze
|
60
|
+
|
61
|
+
# GET /suppression/#{type}/
|
62
|
+
def suppression_get(suppression_type, start_time:, end_time:, limit: 100, offset: 0)
|
63
|
+
unless SUPPRESSION_TYPES.include?(suppression_type.to_s)
|
64
|
+
# 警告のみ
|
65
|
+
Rails.logger.error("Unknown suppresssion type '#{suppression_type}'")
|
66
|
+
end
|
67
|
+
|
68
|
+
params = {
|
69
|
+
start_time: start_time.to_i,
|
70
|
+
end_time: end_time.to_i,
|
71
|
+
limit: limit,
|
72
|
+
offset: offset,
|
73
|
+
}
|
74
|
+
res = client.suppression._(suppression_type).get(query_params: params)
|
75
|
+
@last_response = Response.new(res)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def build_mail(mail_from, mail_from_name, mail_to, subject, body)
|
81
|
+
from = SendGrid::Email.new(email: mail_from, name: mail_from_name)
|
82
|
+
to = SendGrid::Email.new(email: mail_to)
|
83
|
+
content = SendGrid::Content.new(type: 'text/plain', value: body)
|
84
|
+
|
85
|
+
SendGrid::Mail.new(from, subject, to, content)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'sendgrid-ruby'
|
2
|
+
|
3
|
+
module SendgridNotification
|
4
|
+
class SendgridMailer
|
5
|
+
prepend MailRecordable
|
6
|
+
|
7
|
+
class Error < StandardError; end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@from = Rails.application.config.sendgrid_notification.mail_from
|
11
|
+
@from_name = Rails.application.config.sendgrid_notification.mail_from_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def sendmail(to, notification_mail, params = {})
|
15
|
+
body = notification_mail.apply(params)
|
16
|
+
_sendmail(to, notification_mail, body)
|
17
|
+
end
|
18
|
+
|
19
|
+
def last_result
|
20
|
+
# SendGrid::Response class
|
21
|
+
# https://github.com/sendgrid/ruby-http-client/blob/master/lib/ruby_http_client.rb
|
22
|
+
sendgrid_client.last_response
|
23
|
+
end
|
24
|
+
|
25
|
+
def last_result_success?
|
26
|
+
sendgrid_client.last_response.try!(:success?)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def sendgrid_client
|
32
|
+
@sendgrid_client ||= SendgridClient.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def _sendmail(to, notification_mail, body)
|
36
|
+
sendgrid_client.mail_send(
|
37
|
+
from: @from,
|
38
|
+
from_name: @from_name,
|
39
|
+
to: to,
|
40
|
+
subject: notification_mail.subject,
|
41
|
+
body: body
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'sendgrid-ruby'
|
2
|
+
|
3
|
+
module SendgridNotification
|
4
|
+
class SendgridStatus
|
5
|
+
class RetrieveError < ::StandardError; end
|
6
|
+
|
7
|
+
# mapped to sendgrid api result
|
8
|
+
# e.g. https://sendgrid.com/docs/API_Reference/Web_API_v3/blocks.html
|
9
|
+
# ( なお invalid_emails には status がない。そもそも送っていないから。 )
|
10
|
+
Suppression = Struct.new(:type, :created, :email, :reason, :status) do
|
11
|
+
def self.build(type, hash)
|
12
|
+
new(type, *hash.values_at('created', 'email', 'reason', 'status'))
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
to_h.to_json
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.auto_update
|
21
|
+
last = SendgridStatusUpdateHistory.last
|
22
|
+
start_time = last ? last.end_time : 1.hour.ago.to_i
|
23
|
+
end_time = Time.now.to_i
|
24
|
+
|
25
|
+
suppressions = update(start_time, end_time)
|
26
|
+
|
27
|
+
SendgridStatusUpdateHistory.create!(
|
28
|
+
start_time: start_time,
|
29
|
+
end_time: end_time,
|
30
|
+
count: suppressions.size,
|
31
|
+
body: suppressions.map(&:to_s).join("\n")
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
# TODO: 前回の保存日時からの内容を記録
|
36
|
+
def self.update(start_time = 1.hour.ago, end_time = Time.now)
|
37
|
+
suppressions = retrieve_all(start_time, end_time)
|
38
|
+
suppressions.each do |s|
|
39
|
+
update_mail_history(s.email, s.created, s.type, s.reason)
|
40
|
+
end
|
41
|
+
suppressions
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.retrieve_all(start_time, end_time)
|
45
|
+
SendgridClient::SUPPRESSION_TYPES.each_with_object([]) do |type, suppressions|
|
46
|
+
result = retrieve(type, start_time, end_time)
|
47
|
+
suppressions.concat result
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# type is one of SendgridClient::SUPPRESSION_TYPES
|
52
|
+
# {start,end}_time is Time or Integer
|
53
|
+
def self.retrieve(type, start_time, end_time, limit = 100)
|
54
|
+
_client = client
|
55
|
+
offset = 0
|
56
|
+
suppressions = []
|
57
|
+
begin
|
58
|
+
res = _client.suppression_get(type,
|
59
|
+
start_time: start_time.to_i, end_time: end_time.to_i,
|
60
|
+
limit: limit, offset: offset)
|
61
|
+
# FIXME: if timeout?
|
62
|
+
if res.success?
|
63
|
+
# res.body is type of [{}]
|
64
|
+
results = res.body.map { |h| Suppression.build(type.to_s, h) }
|
65
|
+
suppressions.concat results
|
66
|
+
else
|
67
|
+
# Rails.logger.warn "sendgrid returns status code #{res.status_code}. (#{type}, #{start_time}, #{end_time})"
|
68
|
+
raise RetrieveError, "sendgrid returns status code #{res.status_code}. (#{type}, #{start_time}, #{end_time})"
|
69
|
+
end
|
70
|
+
offset += limit
|
71
|
+
end while results.size == limit
|
72
|
+
suppressions
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.client
|
76
|
+
SendgridClient.new
|
77
|
+
end
|
78
|
+
|
79
|
+
# status_timestamp allows Integer unix timestamp
|
80
|
+
def self.update_mail_history(mailto, status_timestamp, error_type, error_reason, relation = MailHistory.all)
|
81
|
+
target = relation.order(:sent_at).where(to: mailto).where('sent_at <= ?', Time.at(status_timestamp)).first
|
82
|
+
if target
|
83
|
+
target.update!(error_type: error_type, error_reason: error_reason)
|
84
|
+
else
|
85
|
+
Rails.logger.warn("SendgridStatus::Updater#update: Fail to find history; mailto: #{mailto}, created: #{status_timestamp}, error_type: #{error_type}, error_reason: #{error_reason}")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SendgridNotification
|
2
|
+
class SendgridStatusUpdateHistory < ActiveRecord::Base
|
3
|
+
with_options numericality: { only_integer: true } do
|
4
|
+
validates :start_time
|
5
|
+
validates :end_time
|
6
|
+
end
|
7
|
+
|
8
|
+
def start_time_in_time_zone
|
9
|
+
Time.zone.at(start_time)
|
10
|
+
end
|
11
|
+
|
12
|
+
def end_time_in_time_zone
|
13
|
+
Time.zone.at(end_time)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module SendgridNotification
|
2
|
+
class TemplateParametersValidator < ActiveModel::Validator
|
3
|
+
def initialize(options)
|
4
|
+
@parameter_keys ||= Array(options[:parameters]) || []
|
5
|
+
end
|
6
|
+
|
7
|
+
def validate(record)
|
8
|
+
params = @parameter_keys.map{|k| [k, k] }.to_h
|
9
|
+
record.apply(params)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Sendgrid notification</title>
|
5
|
+
<%= stylesheet_link_tag "sendgrid_notification/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "sendgrid_notification/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateNotificationMails < ActiveRecord::Migration[5.1]
|
2
|
+
def change
|
3
|
+
create_table :notification_mails do |t|
|
4
|
+
t.string :key, null: false
|
5
|
+
t.string :subject, null: false
|
6
|
+
t.text :content, null: false
|
7
|
+
|
8
|
+
t.timestamps null: false
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :notification_mails, :key, unique: true
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateMailHistories < ActiveRecord::Migration[5.1]
|
2
|
+
def change
|
3
|
+
create_table :mail_histories do |t|
|
4
|
+
t.string :key, null: false
|
5
|
+
t.string :to, null: false
|
6
|
+
t.timestamp :sent_at, null: false
|
7
|
+
t.string :error_type
|
8
|
+
t.text :error_reason
|
9
|
+
|
10
|
+
t.timestamps null: false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateSendgridStatusUpdateHistories < ActiveRecord::Migration[5.1]
|
2
|
+
def change
|
3
|
+
create_table :sendgrid_status_update_histories do |t|
|
4
|
+
t.integer :start_time, null: false
|
5
|
+
t.integer :end_time, null: false
|
6
|
+
t.integer :count
|
7
|
+
t.text :body
|
8
|
+
|
9
|
+
t.timestamps null: false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SendgridNotification
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
config.sendgrid_notification = ActiveSupport::OrderedOptions.new
|
4
|
+
|
5
|
+
initializer "sendgrid_notification.mailer" do |app|
|
6
|
+
app.config.sendgrid_notification.mailer ||= "SendgridNotification::SendgridMailer"
|
7
|
+
# if test or dev, use NullMailer instead
|
8
|
+
end
|
9
|
+
|
10
|
+
initializer "sendgrid_notification.api_key" do |app|
|
11
|
+
app.config.sendgrid_notification.api_key ||= ENV['SENDGRID_API_KEY']
|
12
|
+
end
|
13
|
+
|
14
|
+
initializer "sendgrid_notification.mail_from" do |app|
|
15
|
+
app.config.sendgrid_notification.mail_from ||= ENV['SENDGRID_MAIL_FROM']
|
16
|
+
app.config.sendgrid_notification.mail_from_name ||= ENV['SENDGRID_MAIL_FROM_NAME']
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
namespace :sendgrid_notification do
|
2
|
+
namespace :testmail do
|
3
|
+
desc 'Create notification_mails test record, KEY = "_test"'
|
4
|
+
task init: :environment do
|
5
|
+
key = ENV['KEY'] || '_test'
|
6
|
+
SendgridNotification::NotificationMail.find_or_create_by!(key: key) do |m|
|
7
|
+
m.subject = 'Test mail subject'
|
8
|
+
m.content = <<-EOD
|
9
|
+
This is test mail.
|
10
|
+
{{ body }}
|
11
|
+
EOD
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Send testmail (TO=address [body=body])'
|
16
|
+
task send: :environment do
|
17
|
+
ENV['KEY'] ||= '_test'
|
18
|
+
ARGV << 'body=[body parameter expected]' unless ENV['body']
|
19
|
+
Rake::Task["sendgrid_notification:send"].invoke
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Send mail (TO=address KEY=mail_key and describe parameter...)'
|
24
|
+
task send: :environment do
|
25
|
+
to = ENV.fetch('TO')
|
26
|
+
key = ENV.fetch('KEY')
|
27
|
+
params = ARGV.each_with_object({}) do |arg, hash|
|
28
|
+
hash[Regexp.last_match(1)] = Regexp.last_match(2) if arg =~ /^(\w+)=(.*)$/m
|
29
|
+
end
|
30
|
+
|
31
|
+
m = SendgridNotification::NotificationMail.find_by!(key: key)
|
32
|
+
m.sendmail(to, params)
|
33
|
+
end
|
34
|
+
|
35
|
+
namespace :status do
|
36
|
+
desc 'update status (start=datetime end=datetime)'
|
37
|
+
task update: :environment do
|
38
|
+
start_time = Time.parse ENV.fetch('start')
|
39
|
+
end_time = Time.parse ENV.fetch('end')
|
40
|
+
SendgridNotification::SendgridStatus.update(start_time, end_time)
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'update status after previous autoupdate'
|
44
|
+
task autoupdate: :environment do
|
45
|
+
SendgridNotification::SendgridStatus.auto_update
|
46
|
+
end
|
47
|
+
|
48
|
+
desc 'only retrieve suppression statuses (start=datetime end=datetime)'
|
49
|
+
task retrieve: :environment do
|
50
|
+
start_time = Time.parse ENV.fetch('start')
|
51
|
+
end_time = Time.parse ENV.fetch('end')
|
52
|
+
suppressions = SendgridNotification::SendgridStatus.retrieve_all(start_time, end_time)
|
53
|
+
puts suppressions
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sendgrid_notification
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- HORII Keima
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-08-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sendgrid-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-power_assert
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: factory_girl_rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard-minitest
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest-rg
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: notification mail sender via sendgrid API
|
126
|
+
email:
|
127
|
+
- holysugar@gmail.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- MIT-LICENSE
|
133
|
+
- README.md
|
134
|
+
- Rakefile
|
135
|
+
- app/assets/config/sendgrid_notification_manifest.js
|
136
|
+
- app/assets/javascripts/sendgrid_notification/application.js
|
137
|
+
- app/assets/stylesheets/sendgrid_notification/application.css
|
138
|
+
- app/controllers/sendgrid_notification/application_controller.rb
|
139
|
+
- app/helpers/sendgrid_notification/application_helper.rb
|
140
|
+
- app/jobs/sendgrid_notification/application_job.rb
|
141
|
+
- app/jobs/sendgrid_notification/sendmail_job.rb
|
142
|
+
- app/mailers/sendgrid_notification/application_mailer.rb
|
143
|
+
- app/models/sendgrid_notification/application_record.rb
|
144
|
+
- app/models/sendgrid_notification/mail_history.rb
|
145
|
+
- app/models/sendgrid_notification/mail_recordable.rb
|
146
|
+
- app/models/sendgrid_notification/notification_mail.rb
|
147
|
+
- app/models/sendgrid_notification/null_mailer.rb
|
148
|
+
- app/models/sendgrid_notification/sendgrid_client.rb
|
149
|
+
- app/models/sendgrid_notification/sendgrid_mailer.rb
|
150
|
+
- app/models/sendgrid_notification/sendgrid_status.rb
|
151
|
+
- app/models/sendgrid_notification/sendgrid_status_update_history.rb
|
152
|
+
- app/models/sendgrid_notification/template_parameters_validator.rb
|
153
|
+
- app/views/layouts/sendgrid_notification/application.html.erb
|
154
|
+
- config/routes.rb
|
155
|
+
- db/migrate/20170208085706_create_notification_mails.rb
|
156
|
+
- db/migrate/20170208113843_create_mail_histories.rb
|
157
|
+
- db/migrate/20170217072256_create_sendgrid_status_update_histories.rb
|
158
|
+
- lib/sendgrid_notification.rb
|
159
|
+
- lib/sendgrid_notification/engine.rb
|
160
|
+
- lib/sendgrid_notification/version.rb
|
161
|
+
- lib/tasks/sendgrid_notification_tasks.rake
|
162
|
+
homepage: https://github.com/holysugar/sendgrid_notification
|
163
|
+
licenses:
|
164
|
+
- MIT
|
165
|
+
metadata: {}
|
166
|
+
post_install_message:
|
167
|
+
rdoc_options: []
|
168
|
+
require_paths:
|
169
|
+
- lib
|
170
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
requirements: []
|
181
|
+
rubyforge_project:
|
182
|
+
rubygems_version: 2.6.11
|
183
|
+
signing_key:
|
184
|
+
specification_version: 4
|
185
|
+
summary: notification mail sender via sendgrid API
|
186
|
+
test_files: []
|