aws-ses 0.6.0 → 0.7.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 +4 -4
- data/CHANGELOG +8 -1
- data/Gemfile +8 -5
- data/Gemfile.lock +59 -1
- data/README.erb +7 -4
- data/README.rdoc +13 -8
- data/Rakefile +14 -0
- data/VERSION +1 -1
- data/aws-ses.gemspec +48 -42
- data/lib/aws/ses/base.rb +93 -14
- data/lib/aws/ses/send_email.rb +1 -1
- data/test/base_test.rb +65 -0
- data/test/helper.rb +1 -0
- data/test/send_email_test.rb +21 -0
- metadata +90 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05f8041ea9198a602f2ce4882d6e97cc02975836
|
4
|
+
data.tar.gz: 751a555c98abe3962855fa0cc68e4048215e5c02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d42dc94c62bf6379c1f8bb4ebeb62203270a1b786bbed459138b6cb1912260822621f4ec753d3ad1c7c244a0d56e2b730f289c30a5a133dc41b34a5be75d2de
|
7
|
+
data.tar.gz: 68b570b0043c013cd72858d0136840357b99f5110eacec9a09e7f1f30a008dbd65af8042d7b8d71fca5c454662e1becb941ef4c94b112112c0527fecebd47519
|
data/CHANGELOG
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0:
|
2
|
+
* Implement Authorization Header v4 (add config: `signature_version: 4`)
|
3
|
+
* Wrap message ID in `<>` correctly
|
4
|
+
|
5
|
+
0.6.0:
|
6
|
+
* Various small bug fixes
|
7
|
+
|
8
|
+
0.5.0:
|
2
9
|
* Check for existence of html or text body when attachments are included
|
3
10
|
* Message ids in mail objects should now reflect what is actually sent.
|
4
11
|
|
data/Gemfile
CHANGED
@@ -6,13 +6,16 @@ source "http://rubygems.org"
|
|
6
6
|
# Add dependencies to develop your gem here.
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
8
8
|
group :development do
|
9
|
-
gem "
|
10
|
-
gem "bundler"
|
11
|
-
#gem "rcov", ">= 0"
|
9
|
+
gem "bundler", ">= 1.17"
|
12
10
|
gem 'flexmock', '~> 0.8.11'
|
11
|
+
gem "jeweler"
|
12
|
+
gem "rake"
|
13
|
+
gem "shoulda-context", ">= 0"
|
14
|
+
gem 'test-unit'
|
15
|
+
gem 'timecop'
|
13
16
|
end
|
14
17
|
|
15
|
-
gem 'xml-simple'
|
16
18
|
gem 'builder'
|
17
|
-
gem 'mime-types'
|
18
19
|
gem 'mail', '> 2.2.5'
|
20
|
+
gem 'mime-types'
|
21
|
+
gem 'xml-simple'
|
data/Gemfile.lock
CHANGED
@@ -1,12 +1,63 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
+
addressable (2.4.0)
|
4
5
|
builder (3.2.2)
|
6
|
+
descendants_tracker (0.0.4)
|
7
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
8
|
+
faraday (0.9.2)
|
9
|
+
multipart-post (>= 1.2, < 3)
|
5
10
|
flexmock (0.8.11)
|
11
|
+
git (1.7.0)
|
12
|
+
rchardet (~> 1.8)
|
13
|
+
github_api (0.16.0)
|
14
|
+
addressable (~> 2.4.0)
|
15
|
+
descendants_tracker (~> 0.0.4)
|
16
|
+
faraday (~> 0.8, < 0.10)
|
17
|
+
hashie (>= 3.4)
|
18
|
+
mime-types (>= 1.16, < 3.0)
|
19
|
+
oauth2 (~> 1.0)
|
20
|
+
hashie (4.1.0)
|
21
|
+
highline (2.0.3)
|
22
|
+
jeweler (2.3.9)
|
23
|
+
builder
|
24
|
+
bundler
|
25
|
+
git (>= 1.2.5)
|
26
|
+
github_api (~> 0.16.0)
|
27
|
+
highline (>= 1.6.15)
|
28
|
+
nokogiri (>= 1.5.10)
|
29
|
+
psych
|
30
|
+
rake
|
31
|
+
rdoc
|
32
|
+
semver2
|
33
|
+
jwt (2.2.2)
|
6
34
|
mail (2.6.1)
|
7
35
|
mime-types (>= 1.16, < 3)
|
8
36
|
mime-types (2.4.1)
|
37
|
+
mini_portile2 (2.4.0)
|
38
|
+
multi_json (1.15.0)
|
39
|
+
multi_xml (0.6.0)
|
40
|
+
multipart-post (2.1.1)
|
41
|
+
nokogiri (1.10.10)
|
42
|
+
mini_portile2 (~> 2.4.0)
|
43
|
+
oauth2 (1.4.4)
|
44
|
+
faraday (>= 0.8, < 2.0)
|
45
|
+
jwt (>= 1.0, < 3.0)
|
46
|
+
multi_json (~> 1.3)
|
47
|
+
multi_xml (~> 0.5)
|
48
|
+
rack (>= 1.2, < 3)
|
49
|
+
power_assert (1.2.0)
|
50
|
+
psych (3.1.0)
|
51
|
+
rack (2.2.3)
|
52
|
+
rake (13.0.1)
|
53
|
+
rchardet (1.8.0)
|
54
|
+
rdoc (6.2.0)
|
55
|
+
semver2 (3.4.2)
|
9
56
|
shoulda-context (1.2.1)
|
57
|
+
test-unit (3.3.6)
|
58
|
+
power_assert
|
59
|
+
thread_safe (0.3.6)
|
60
|
+
timecop (0.9.1)
|
10
61
|
xml-simple (1.1.4)
|
11
62
|
|
12
63
|
PLATFORMS
|
@@ -14,9 +65,16 @@ PLATFORMS
|
|
14
65
|
|
15
66
|
DEPENDENCIES
|
16
67
|
builder
|
17
|
-
bundler
|
68
|
+
bundler (>= 1.17)
|
18
69
|
flexmock (~> 0.8.11)
|
70
|
+
jeweler
|
19
71
|
mail (> 2.2.5)
|
20
72
|
mime-types
|
73
|
+
rake
|
21
74
|
shoulda-context
|
75
|
+
test-unit
|
76
|
+
timecop
|
22
77
|
xml-simple
|
78
|
+
|
79
|
+
BUNDLED WITH
|
80
|
+
1.17.3
|
data/README.erb
CHANGED
@@ -16,11 +16,11 @@
|
|
16
16
|
|
17
17
|
== Rails
|
18
18
|
|
19
|
-
This gem is compatible with Rails >= 3.0.0 and
|
19
|
+
This gem is compatible with Rails >= 3.0.0 and Ruby 2.3.x
|
20
20
|
|
21
21
|
To use, first add the gem to your Gemfile:
|
22
22
|
|
23
|
-
gem "aws-ses", "~> 0.
|
23
|
+
gem "aws-ses", "~> 0.7.0", :require => 'aws/ses'
|
24
24
|
|
25
25
|
== For Rails 3.x
|
26
26
|
|
@@ -28,7 +28,8 @@ Then, add your Amazon credentials and extend ActionMailer in `config/initializer
|
|
28
28
|
|
29
29
|
ActionMailer::Base.add_delivery_method :ses, AWS::SES::Base,
|
30
30
|
:access_key_id => 'abc',
|
31
|
-
:secret_access_key => '123'
|
31
|
+
:secret_access_key => '123',
|
32
|
+
:signature_version => 4
|
32
33
|
|
33
34
|
Then set the delivery method in `config/environments/*rb` as appropriate:
|
34
35
|
|
@@ -77,7 +78,7 @@ Available at: https://github.com/drewblas/aws-ses
|
|
77
78
|
|
78
79
|
== Copyright
|
79
80
|
|
80
|
-
Copyright (c)
|
81
|
+
Copyright (c) 2020 Drew Blas. See LICENSE for further details.
|
81
82
|
|
82
83
|
== Thanks
|
83
84
|
|
@@ -90,3 +91,5 @@ Special thanks to Marcel Molina Jr. for his creation of AWS::S3 which I used por
|
|
90
91
|
* sshaw
|
91
92
|
* teeparham (documentation)
|
92
93
|
* pzb
|
94
|
+
* NicholasHely
|
95
|
+
* m33h
|
data/README.rdoc
CHANGED
@@ -28,7 +28,8 @@ To connect to a different one, just pass it as a parameter to the AWS::SES::Base
|
|
28
28
|
ses = AWS::SES::Base.new(
|
29
29
|
:access_key_id => 'abc',
|
30
30
|
:secret_access_key => '123',
|
31
|
-
:server => 'email.eu-west-1.amazonaws.com'
|
31
|
+
:server => 'email.eu-west-1.amazonaws.com',
|
32
|
+
:message_id_domain => 'eu-west-1.amazonses.com'
|
32
33
|
)
|
33
34
|
|
34
35
|
== Send E-mail
|
@@ -134,14 +135,13 @@ will return:
|
|
134
135
|
"Rejects"=>"0",
|
135
136
|
"Complaints"=>"0"}]
|
136
137
|
|
137
|
-
|
138
138
|
== Rails
|
139
139
|
|
140
|
-
This gem is compatible with Rails >= 3.0.0 and
|
140
|
+
This gem is compatible with Rails >= 3.0.0 and Ruby 2.3.x
|
141
141
|
|
142
142
|
To use, first add the gem to your Gemfile:
|
143
143
|
|
144
|
-
gem "aws-ses", "~> 0.
|
144
|
+
gem "aws-ses", "~> 0.7.0", :require => 'aws/ses'
|
145
145
|
|
146
146
|
== For Rails 3.x
|
147
147
|
|
@@ -149,9 +149,10 @@ Then, add your Amazon credentials and extend ActionMailer in `config/initializer
|
|
149
149
|
|
150
150
|
ActionMailer::Base.add_delivery_method :ses, AWS::SES::Base,
|
151
151
|
:access_key_id => 'abc',
|
152
|
-
:secret_access_key => '123'
|
152
|
+
:secret_access_key => '123',
|
153
|
+
:signature_version => 4
|
153
154
|
|
154
|
-
Then set the delivery method in `config/environments
|
155
|
+
Then set the delivery method in `config/environments/*.rb` as appropriate:
|
155
156
|
|
156
157
|
config.action_mailer.delivery_method = :ses
|
157
158
|
|
@@ -179,8 +180,12 @@ It means that you are not running with SSL enabled in ruby. Re-compile ruby wit
|
|
179
180
|
If you are receiving this message and you HAVE verified the [source] please <b>check to be sure you are not in sandbox mode!</b>
|
180
181
|
"Email address is not verified.MessageRejected (AWS::Error)"
|
181
182
|
If you have not been granted production access, you will have to <b>verify all recipients</b> as well.
|
182
|
-
|
183
|
-
|
183
|
+
|
184
|
+
To verify email addresses and domains:
|
185
|
+
https://docs.aws.amazon.com/ses/latest/DeveloperGuide/verify-addresses-and-domains.html
|
186
|
+
|
187
|
+
To request production access:
|
188
|
+
https://docs.aws.amazon.com/ses/latest/DeveloperGuide/request-production-access.html
|
184
189
|
|
185
190
|
== Source
|
186
191
|
|
data/Rakefile
CHANGED
@@ -67,3 +67,17 @@ namespace :doc do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
70
|
+
|
71
|
+
require 'jeweler'
|
72
|
+
Jeweler::Tasks.new do |gem|
|
73
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
74
|
+
gem.name = "aws-ses"
|
75
|
+
gem.homepage = "http://github.com/drewblas/aws-ses"
|
76
|
+
gem.license = "MIT"
|
77
|
+
gem.summary = "Client library for Amazon's Simple Email Service's REST API"
|
78
|
+
gem.description = "Client library for Amazon's Simple Email Service's REST API"
|
79
|
+
gem.email = "drew.blas@gmail.com"
|
80
|
+
gem.authors = ["Drew Blas", "Marcel Molina Jr."]
|
81
|
+
# dependencies defined in Gemfile
|
82
|
+
end
|
83
|
+
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/aws-ses.gemspec
CHANGED
@@ -2,17 +2,20 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: aws-ses 0.7.0 ruby lib
|
5
6
|
|
6
7
|
Gem::Specification.new do |s|
|
7
|
-
s.name = "aws-ses"
|
8
|
-
s.version = "0.
|
8
|
+
s.name = "aws-ses".freeze
|
9
|
+
s.version = "0.7.0"
|
9
10
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
s.
|
14
|
-
s.
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib".freeze]
|
13
|
+
s.authors = ["Drew Blas".freeze, "Marcel Molina Jr.".freeze]
|
14
|
+
s.date = "2020-09-03"
|
15
|
+
s.description = "Client library for Amazon's Simple Email Service's REST API".freeze
|
16
|
+
s.email = "drew.blas@gmail.com".freeze
|
15
17
|
s.extra_rdoc_files = [
|
18
|
+
"CHANGELOG",
|
16
19
|
"LICENSE",
|
17
20
|
"README.erb",
|
18
21
|
"README.rdoc",
|
@@ -49,48 +52,51 @@ Gem::Specification.new do |s|
|
|
49
52
|
"test/response_test.rb",
|
50
53
|
"test/send_email_test.rb"
|
51
54
|
]
|
52
|
-
s.homepage = "http://github.com/drewblas/aws-ses"
|
53
|
-
s.licenses = ["MIT"]
|
54
|
-
s.
|
55
|
-
s.
|
56
|
-
s.summary = "Client library for Amazon's Simple Email Service's REST API"
|
57
|
-
s.test_files = [
|
58
|
-
"test/address_test.rb",
|
59
|
-
"test/base_test.rb",
|
60
|
-
"test/extensions_test.rb",
|
61
|
-
"test/fixtures.rb",
|
62
|
-
"test/helper.rb",
|
63
|
-
"test/info_test.rb",
|
64
|
-
"test/mocks/fake_response.rb",
|
65
|
-
"test/response_test.rb",
|
66
|
-
"test/send_email_test.rb"
|
67
|
-
]
|
55
|
+
s.homepage = "http://github.com/drewblas/aws-ses".freeze
|
56
|
+
s.licenses = ["MIT".freeze]
|
57
|
+
s.rubygems_version = "2.5.2.3".freeze
|
58
|
+
s.summary = "Client library for Amazon's Simple Email Service's REST API".freeze
|
68
59
|
|
69
60
|
if s.respond_to? :specification_version then
|
70
|
-
s.specification_version =
|
61
|
+
s.specification_version = 4
|
71
62
|
|
72
63
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
73
|
-
s.add_runtime_dependency(%q<
|
74
|
-
s.add_runtime_dependency(%q<
|
75
|
-
s.add_runtime_dependency(%q<mime-types
|
76
|
-
s.add_runtime_dependency(%q<
|
77
|
-
s.add_development_dependency(%q<
|
78
|
-
s.add_development_dependency(%q<flexmock
|
64
|
+
s.add_runtime_dependency(%q<builder>.freeze, [">= 0"])
|
65
|
+
s.add_runtime_dependency(%q<mail>.freeze, ["> 2.2.5"])
|
66
|
+
s.add_runtime_dependency(%q<mime-types>.freeze, [">= 0"])
|
67
|
+
s.add_runtime_dependency(%q<xml-simple>.freeze, [">= 0"])
|
68
|
+
s.add_development_dependency(%q<bundler>.freeze, [">= 1.17"])
|
69
|
+
s.add_development_dependency(%q<flexmock>.freeze, ["~> 0.8.11"])
|
70
|
+
s.add_development_dependency(%q<jeweler>.freeze, [">= 0"])
|
71
|
+
s.add_development_dependency(%q<rake>.freeze, [">= 0"])
|
72
|
+
s.add_development_dependency(%q<shoulda-context>.freeze, [">= 0"])
|
73
|
+
s.add_development_dependency(%q<test-unit>.freeze, [">= 0"])
|
74
|
+
s.add_development_dependency(%q<timecop>.freeze, [">= 0"])
|
79
75
|
else
|
80
|
-
s.add_dependency(%q<
|
81
|
-
s.add_dependency(%q<
|
82
|
-
s.add_dependency(%q<mime-types
|
83
|
-
s.add_dependency(%q<
|
84
|
-
s.add_dependency(%q<
|
85
|
-
s.add_dependency(%q<flexmock
|
76
|
+
s.add_dependency(%q<builder>.freeze, [">= 0"])
|
77
|
+
s.add_dependency(%q<mail>.freeze, ["> 2.2.5"])
|
78
|
+
s.add_dependency(%q<mime-types>.freeze, [">= 0"])
|
79
|
+
s.add_dependency(%q<xml-simple>.freeze, [">= 0"])
|
80
|
+
s.add_dependency(%q<bundler>.freeze, [">= 1.17"])
|
81
|
+
s.add_dependency(%q<flexmock>.freeze, ["~> 0.8.11"])
|
82
|
+
s.add_dependency(%q<jeweler>.freeze, [">= 0"])
|
83
|
+
s.add_dependency(%q<rake>.freeze, [">= 0"])
|
84
|
+
s.add_dependency(%q<shoulda-context>.freeze, [">= 0"])
|
85
|
+
s.add_dependency(%q<test-unit>.freeze, [">= 0"])
|
86
|
+
s.add_dependency(%q<timecop>.freeze, [">= 0"])
|
86
87
|
end
|
87
88
|
else
|
88
|
-
s.add_dependency(%q<
|
89
|
-
s.add_dependency(%q<
|
90
|
-
s.add_dependency(%q<mime-types
|
91
|
-
s.add_dependency(%q<
|
92
|
-
s.add_dependency(%q<
|
93
|
-
s.add_dependency(%q<flexmock
|
89
|
+
s.add_dependency(%q<builder>.freeze, [">= 0"])
|
90
|
+
s.add_dependency(%q<mail>.freeze, ["> 2.2.5"])
|
91
|
+
s.add_dependency(%q<mime-types>.freeze, [">= 0"])
|
92
|
+
s.add_dependency(%q<xml-simple>.freeze, [">= 0"])
|
93
|
+
s.add_dependency(%q<bundler>.freeze, [">= 1.17"])
|
94
|
+
s.add_dependency(%q<flexmock>.freeze, ["~> 0.8.11"])
|
95
|
+
s.add_dependency(%q<jeweler>.freeze, [">= 0"])
|
96
|
+
s.add_dependency(%q<rake>.freeze, [">= 0"])
|
97
|
+
s.add_dependency(%q<shoulda-context>.freeze, [">= 0"])
|
98
|
+
s.add_dependency(%q<test-unit>.freeze, [">= 0"])
|
99
|
+
s.add_dependency(%q<timecop>.freeze, [">= 0"])
|
94
100
|
end
|
95
101
|
end
|
96
102
|
|
data/lib/aws/ses/base.rb
CHANGED
@@ -26,14 +26,22 @@ module AWS #:nodoc:
|
|
26
26
|
# ses = AWS::SES::Base.new(
|
27
27
|
# :access_key_id => 'abc',
|
28
28
|
# :secret_access_key => '123',
|
29
|
-
# :server => 'email.eu-west-1.amazonaws.com'
|
29
|
+
# :server => 'email.eu-west-1.amazonaws.com',
|
30
|
+
# :message_id_domain => 'eu-west-1.amazonses.com'
|
30
31
|
# )
|
32
|
+
#
|
31
33
|
|
32
34
|
module SES
|
33
35
|
|
34
36
|
API_VERSION = '2010-12-01'
|
35
|
-
|
37
|
+
|
38
|
+
DEFAULT_REGION = 'us-east-1'
|
39
|
+
|
40
|
+
SERVICE = 'ec2'
|
41
|
+
|
36
42
|
DEFAULT_HOST = 'email.us-east-1.amazonaws.com'
|
43
|
+
|
44
|
+
DEFAULT_MESSAGE_ID_DOMAIN = 'email.amazonses.com'
|
37
45
|
|
38
46
|
USER_AGENT = 'github-aws-ses-ruby-gem'
|
39
47
|
|
@@ -67,13 +75,17 @@ module AWS #:nodoc:
|
|
67
75
|
def SES.authorization_header(key, alg, sig)
|
68
76
|
"AWS3-HTTPS AWSAccessKeyId=#{key}, Algorithm=#{alg}, Signature=#{sig}"
|
69
77
|
end
|
70
|
-
|
78
|
+
|
79
|
+
def SES.authorization_header_v4(credential, signed_headers, signature)
|
80
|
+
"AWS4-HMAC-SHA256 Credential=#{credential}, SignedHeaders=#{signed_headers}, Signature=#{signature}"
|
81
|
+
end
|
82
|
+
|
71
83
|
# AWS::SES::Base is the abstract super class of all classes who make requests against SES
|
72
84
|
class Base
|
73
85
|
include SendEmail
|
74
86
|
include Info
|
75
87
|
|
76
|
-
attr_reader :use_ssl, :server, :proxy_server, :port
|
88
|
+
attr_reader :use_ssl, :server, :proxy_server, :port, :message_id_domain, :signature_version, :region
|
77
89
|
attr_accessor :settings
|
78
90
|
|
79
91
|
# @option options [String] :access_key_id ("") The user's AWS Access Key ID
|
@@ -82,6 +94,8 @@ module AWS #:nodoc:
|
|
82
94
|
# @option options [String] :server ("email.us-east-1.amazonaws.com") The server API endpoint host
|
83
95
|
# @option options [String] :proxy_server (nil) An HTTP proxy server FQDN
|
84
96
|
# @option options [String] :user_agent ("github-aws-ses-ruby-gem") The HTTP User-Agent header value
|
97
|
+
# @option options [String] :region ("us-east-1") The server API endpoint host
|
98
|
+
# @option options [String] :message_id_domain ("us-east-1.amazonses.com") Domain used to build message_id header
|
85
99
|
# @return [Object] the object.
|
86
100
|
def initialize( options = {} )
|
87
101
|
|
@@ -89,16 +103,21 @@ module AWS #:nodoc:
|
|
89
103
|
:secret_access_key => "",
|
90
104
|
:use_ssl => true,
|
91
105
|
:server => DEFAULT_HOST,
|
106
|
+
:message_id_domain => DEFAULT_MESSAGE_ID_DOMAIN,
|
92
107
|
:path => "/",
|
93
108
|
:user_agent => USER_AGENT,
|
94
|
-
:proxy_server => nil
|
109
|
+
:proxy_server => nil,
|
110
|
+
:region => DEFAULT_REGION
|
95
111
|
}.merge(options)
|
96
112
|
|
113
|
+
@signature_version = options[:signature_version] || 2
|
97
114
|
@server = options[:server]
|
115
|
+
@message_id_domain = options[:message_id_domain]
|
98
116
|
@proxy_server = options[:proxy_server]
|
99
117
|
@use_ssl = options[:use_ssl]
|
100
118
|
@path = options[:path]
|
101
119
|
@user_agent = options[:user_agent]
|
120
|
+
@region = options[:region]
|
102
121
|
@settings = {}
|
103
122
|
|
104
123
|
raise ArgumentError, "No :access_key_id provided" if options[:access_key_id].nil? || options[:access_key_id].empty?
|
@@ -130,10 +149,6 @@ module AWS #:nodoc:
|
|
130
149
|
proxy.password).new(options[:server], @port)
|
131
150
|
|
132
151
|
@http.use_ssl = @use_ssl
|
133
|
-
|
134
|
-
# Don't verify the SSL certificates. Avoids SSL Cert warning in log on every GET.
|
135
|
-
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
136
|
-
|
137
152
|
end
|
138
153
|
|
139
154
|
def connection
|
@@ -150,7 +165,7 @@ module AWS #:nodoc:
|
|
150
165
|
timestamp = Time.now.getutc
|
151
166
|
|
152
167
|
params.merge!( {"Action" => action,
|
153
|
-
"SignatureVersion" =>
|
168
|
+
"SignatureVersion" => signature_version.to_s,
|
154
169
|
"SignatureMethod" => 'HmacSHA256',
|
155
170
|
"AWSAccessKeyId" => @access_key_id,
|
156
171
|
"Version" => API_VERSION,
|
@@ -162,9 +177,9 @@ module AWS #:nodoc:
|
|
162
177
|
|
163
178
|
req = {}
|
164
179
|
|
165
|
-
req['X-Amzn-Authorization'] = get_aws_auth_param(timestamp.httpdate, @secret_access_key)
|
180
|
+
req['X-Amzn-Authorization'] = get_aws_auth_param(timestamp.httpdate, @secret_access_key, action, signature_version.to_s)
|
166
181
|
req['Date'] = timestamp.httpdate
|
167
|
-
req['User-Agent'] = @user_agent
|
182
|
+
req['User-Agent'] = @user_agent
|
168
183
|
|
169
184
|
response = connection.post(@path, query, req)
|
170
185
|
|
@@ -179,9 +194,73 @@ module AWS #:nodoc:
|
|
179
194
|
end
|
180
195
|
|
181
196
|
# Set the Authorization header using AWS signed header authentication
|
182
|
-
def get_aws_auth_param(timestamp, secret_access_key)
|
197
|
+
def get_aws_auth_param(timestamp, secret_access_key, action = '', signature_version = 2)
|
183
198
|
encoded_canonical = SES.encode(secret_access_key, timestamp, false)
|
184
|
-
SES.authorization_header(@access_key_id, 'HmacSHA256', encoded_canonical)
|
199
|
+
return SES.authorization_header(@access_key_id, 'HmacSHA256', encoded_canonical) unless signature_version == 4
|
200
|
+
|
201
|
+
SES.authorization_header_v4(sig_v4_auth_credential, sig_v4_auth_signed_headers, sig_v4_auth_signature(action))
|
202
|
+
end
|
203
|
+
|
204
|
+
private
|
205
|
+
|
206
|
+
def sig_v4_auth_credential
|
207
|
+
@access_key_id + '/' + credential_scope
|
208
|
+
end
|
209
|
+
|
210
|
+
def sig_v4_auth_signed_headers
|
211
|
+
'host;x-amz-date'
|
212
|
+
end
|
213
|
+
|
214
|
+
def credential_scope
|
215
|
+
datestamp + '/' + region + '/' + SERVICE + '/' + 'aws4_request'
|
216
|
+
end
|
217
|
+
|
218
|
+
def string_to_sign(for_action)
|
219
|
+
"AWS4-HMAC-SHA256\n" + amzdate + "\n" + credential_scope + "\n" + Digest::SHA256.hexdigest(canonical_request(for_action).encode('utf-8').b)
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
def amzdate
|
224
|
+
Time.now.utc.strftime('%Y%m%dT%H%M%SZ')
|
225
|
+
end
|
226
|
+
|
227
|
+
def datestamp
|
228
|
+
Time.now.utc.strftime('%Y%m%d')
|
229
|
+
end
|
230
|
+
|
231
|
+
def canonical_request(for_action)
|
232
|
+
"GET" + "\n" + "/" + "\n" + canonical_querystring(for_action) + "\n" + canonical_headers + "\n" + sig_v4_auth_signed_headers + "\n" + payload_hash
|
233
|
+
end
|
234
|
+
|
235
|
+
def canonical_querystring(action)
|
236
|
+
"Action=#{action}&Version=2013-10-15"
|
237
|
+
end
|
238
|
+
|
239
|
+
def canonical_headers
|
240
|
+
'host:' + server + "\n" + 'x-amz-date:' + amzdate + "\n"
|
241
|
+
end
|
242
|
+
|
243
|
+
def payload_hash
|
244
|
+
Digest::SHA256.hexdigest(''.encode('utf-8'))
|
245
|
+
end
|
246
|
+
|
247
|
+
def sig_v4_auth_signature(for_action)
|
248
|
+
signing_key = getSignatureKey(@secret_access_key, datestamp, region, SERVICE)
|
249
|
+
|
250
|
+
OpenSSL::HMAC.hexdigest("SHA256", signing_key, string_to_sign(for_action).encode('utf-8'))
|
251
|
+
end
|
252
|
+
|
253
|
+
def getSignatureKey(key, dateStamp, regionName, serviceName)
|
254
|
+
kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
|
255
|
+
kRegion = sign(kDate, regionName)
|
256
|
+
kService = sign(kRegion, serviceName)
|
257
|
+
kSigning = sign(kService, 'aws4_request')
|
258
|
+
|
259
|
+
kSigning
|
260
|
+
end
|
261
|
+
|
262
|
+
def sign(key, msg)
|
263
|
+
OpenSSL::HMAC.digest("SHA256", key, msg.encode('utf-8'))
|
185
264
|
end
|
186
265
|
end # class Base
|
187
266
|
end # Module SES
|
data/lib/aws/ses/send_email.rb
CHANGED
@@ -101,7 +101,7 @@ module AWS
|
|
101
101
|
|
102
102
|
raw_email = build_raw_email(message, args)
|
103
103
|
result = request('SendRawEmail', raw_email)
|
104
|
-
message.message_id = "
|
104
|
+
message.message_id = "<#{result.parsed['SendRawEmailResult']['MessageId']}@#{message_id_domain}>"
|
105
105
|
result
|
106
106
|
end
|
107
107
|
|
data/test/base_test.rb
CHANGED
@@ -37,4 +37,69 @@ class BaseTest < Test::Unit::TestCase
|
|
37
37
|
# assert result.error.error?
|
38
38
|
# assert_equal 'ValidationError', result.error.code
|
39
39
|
end
|
40
|
+
|
41
|
+
def test_ses_authorization_header_v2
|
42
|
+
aws_access_key_id = 'fake_aws_key_id'
|
43
|
+
aws_secret_access_key = 'fake_aws_access_key'
|
44
|
+
timestamp = Time.new(2020, 7, 2, 7, 17, 58, '+00:00')
|
45
|
+
|
46
|
+
base = ::AWS::SES::Base.new(
|
47
|
+
access_key_id: aws_access_key_id,
|
48
|
+
secret_access_key: aws_secret_access_key
|
49
|
+
)
|
50
|
+
|
51
|
+
assert_equal 'AWS3-HTTPS AWSAccessKeyId=fake_aws_key_id, Algorithm=HmacSHA256, Signature=eHh/cPIJJUc1+RMCueAi50EPlYxkZNXMrxtGxjkBD1w=', base.get_aws_auth_param(timestamp.httpdate, aws_secret_access_key)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_ses_authorization_header_v4
|
55
|
+
aws_access_key_id = 'fake_aws_key_id'
|
56
|
+
aws_secret_access_key = 'fake_aws_access_key'
|
57
|
+
time = Time.new(2020, 7, 2, 7, 17, 58, '+00:00')
|
58
|
+
::Timecop.freeze(time)
|
59
|
+
|
60
|
+
base = ::AWS::SES::Base.new(
|
61
|
+
server: 'ec2.amazonaws.com',
|
62
|
+
signature_version: 4,
|
63
|
+
access_key_id: aws_access_key_id,
|
64
|
+
secret_access_key: aws_secret_access_key
|
65
|
+
)
|
66
|
+
|
67
|
+
assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=c0465b36efd110b14a1c6dcca3e105085ed2bfb2a3fd3b3586cc459326ab43aa', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions', 4)
|
68
|
+
Timecop.return
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_ses_authorization_header_v4_changed_host
|
72
|
+
aws_access_key_id = 'fake_aws_key_id'
|
73
|
+
aws_secret_access_key = 'fake_aws_access_key'
|
74
|
+
time = Time.new(2020, 7, 2, 7, 17, 58, '+00:00')
|
75
|
+
::Timecop.freeze(time)
|
76
|
+
|
77
|
+
base = ::AWS::SES::Base.new(
|
78
|
+
server: 'email.us-east-1.amazonaws.com',
|
79
|
+
signature_version: 4,
|
80
|
+
access_key_id: aws_access_key_id,
|
81
|
+
secret_access_key: aws_secret_access_key
|
82
|
+
)
|
83
|
+
|
84
|
+
assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions', 4)
|
85
|
+
Timecop.return
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_ses_authorization_header_v4_changed_region
|
89
|
+
aws_access_key_id = 'fake_aws_key_id'
|
90
|
+
aws_secret_access_key = 'fake_aws_access_key'
|
91
|
+
time = Time.new(2020, 7, 2, 7, 17, 58, '+00:00')
|
92
|
+
::Timecop.freeze(time)
|
93
|
+
|
94
|
+
base = ::AWS::SES::Base.new(
|
95
|
+
server: 'email.us-east-1.amazonaws.com',
|
96
|
+
signature_version: 4,
|
97
|
+
access_key_id: aws_access_key_id,
|
98
|
+
secret_access_key: aws_secret_access_key,
|
99
|
+
region: 'eu-west-1'
|
100
|
+
)
|
101
|
+
|
102
|
+
assert_not_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions', 4)
|
103
|
+
Timecop.return
|
104
|
+
end
|
40
105
|
end
|
data/test/helper.rb
CHANGED
data/test/send_email_test.rb
CHANGED
@@ -82,6 +82,27 @@ class SendEmailTest < Test::Unit::TestCase
|
|
82
82
|
assert_equal 'xyz-123', result.request_id
|
83
83
|
end
|
84
84
|
|
85
|
+
should 'send a raw e-mail with a mail object' do
|
86
|
+
mock_connection(@base, :body => %{
|
87
|
+
<SendRawEmailResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
88
|
+
<SendRawEmailResult>
|
89
|
+
<MessageId>abc-123</MessageId>
|
90
|
+
</SendRawEmailResult>
|
91
|
+
<ResponseMetadata>
|
92
|
+
<RequestId>xyz-123</RequestId>
|
93
|
+
</ResponseMetadata>
|
94
|
+
</SendRawEmailResponse>
|
95
|
+
})
|
96
|
+
|
97
|
+
message = Mail.new(@basic_email)
|
98
|
+
result = @base.send_raw_email(message)
|
99
|
+
assert result.success?
|
100
|
+
assert_equal 'abc-123', result.message_id
|
101
|
+
assert_equal 'xyz-123', result.request_id
|
102
|
+
assert message.errors.empty?
|
103
|
+
assert_equal 'abc-123@email.amazonses.com', message.message_id
|
104
|
+
end
|
105
|
+
|
85
106
|
context "with a standard email" do
|
86
107
|
setup do
|
87
108
|
@message = Mail.new({:from => 'jon@example.com', :to => 'dave@example.com', :cc => 'sally@example.com', :subject => 'Subject1', :body => "test body"})
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-ses
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Drew Blas
|
@@ -9,10 +9,10 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-09-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: builder
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
@@ -26,19 +26,19 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: mail
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - ">"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
34
|
+
version: 2.2.5
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - "
|
39
|
+
- - ">"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
41
|
+
version: 2.2.5
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: mime-types
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -54,33 +54,33 @@ dependencies:
|
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
57
|
+
name: xml-simple
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- - "
|
60
|
+
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
62
|
+
version: '0'
|
63
63
|
type: :runtime
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- - "
|
67
|
+
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
69
|
+
version: '0'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
|
-
name:
|
71
|
+
name: bundler
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
74
|
- - ">="
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
76
|
+
version: '1.17'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
81
|
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
83
|
+
version: '1.17'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: flexmock
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,11 +95,82 @@ dependencies:
|
|
95
95
|
- - "~>"
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: 0.8.11
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: jeweler
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: rake
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: shoulda-context
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: test-unit
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: timecop
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
type: :development
|
162
|
+
prerelease: false
|
163
|
+
version_requirements: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
98
168
|
description: Client library for Amazon's Simple Email Service's REST API
|
99
169
|
email: drew.blas@gmail.com
|
100
170
|
executables: []
|
101
171
|
extensions: []
|
102
172
|
extra_rdoc_files:
|
173
|
+
- CHANGELOG
|
103
174
|
- LICENSE
|
104
175
|
- README.erb
|
105
176
|
- README.rdoc
|
@@ -154,17 +225,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
225
|
version: '0'
|
155
226
|
requirements: []
|
156
227
|
rubyforge_project:
|
157
|
-
rubygems_version: 2.2.
|
228
|
+
rubygems_version: 2.5.2.3
|
158
229
|
signing_key:
|
159
|
-
specification_version:
|
230
|
+
specification_version: 4
|
160
231
|
summary: Client library for Amazon's Simple Email Service's REST API
|
161
|
-
test_files:
|
162
|
-
- test/address_test.rb
|
163
|
-
- test/base_test.rb
|
164
|
-
- test/extensions_test.rb
|
165
|
-
- test/fixtures.rb
|
166
|
-
- test/helper.rb
|
167
|
-
- test/info_test.rb
|
168
|
-
- test/mocks/fake_response.rb
|
169
|
-
- test/response_test.rb
|
170
|
-
- test/send_email_test.rb
|
232
|
+
test_files: []
|