aws-ses 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|