ses 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gems +5 -0
- data/.gitignore +5 -0
- data/.rvmrc +1 -0
- data/.travis.yml +15 -0
- data/.yardopts +9 -0
- data/LICENSE +19 -0
- data/README.md +49 -0
- data/Rakefile +3 -0
- data/lib/.gitkeep +0 -0
- data/lib/ses.rb +4 -0
- data/lib/ses/.gitkeep +0 -0
- data/lib/ses/client.rb +122 -0
- data/lib/ses/email.rb +214 -0
- data/lib/ses/errors.rb +15 -0
- data/lib/ses/version.rb +3 -0
- data/pkg/.gitkeep +0 -0
- data/ses.gemspec +21 -0
- data/spec/.gitkeep +0 -0
- data/spec/helper.rb +8 -0
- data/spec/ses/client.rb +44 -0
- data/spec/ses/email.rb +128 -0
- data/task/build.rake +18 -0
- metadata +122 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use --create 1.9.3@ses
|
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2012, Yorick Peterse
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# SES
|
2
|
+
|
3
|
+
SES is a very simple and easy to use Gem for sending Emails using the Amazon SES
|
4
|
+
API. While there are already quite a few Gems out there for using this API most
|
5
|
+
of them had a dependency on the rather bloated "Mail" library.
|
6
|
+
|
7
|
+
This particular Gem aims to be as small as possible, comes with only HTTParty as
|
8
|
+
a dependency and doesn't do anything else besides sending Emails. This means
|
9
|
+
that if you're looking for a way to verify Emails or to get your send quota you
|
10
|
+
should probably look somewhere else.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
$ gem install ses
|
15
|
+
|
16
|
+
## Sending Emails
|
17
|
+
|
18
|
+
Load the gem:
|
19
|
+
|
20
|
+
require 'ses'
|
21
|
+
|
22
|
+
Configure your access and secret keys:
|
23
|
+
|
24
|
+
SES::Client::OPTIONS[:access_key] = 'example'
|
25
|
+
SES::Client::OPTIONS[:secret_key] = 'example'
|
26
|
+
|
27
|
+
Create a new instance of ``SES::Email``:
|
28
|
+
|
29
|
+
email = SES::Email.new(
|
30
|
+
:from => 'user@example.com',
|
31
|
+
:to => 'somebody@example.com',
|
32
|
+
:subject => 'Testing',
|
33
|
+
:body => 'This is an example Email'
|
34
|
+
)
|
35
|
+
|
36
|
+
And send it:
|
37
|
+
|
38
|
+
email.deliver
|
39
|
+
|
40
|
+
## Running Tests
|
41
|
+
|
42
|
+
The tests are written using Bacon and can be executed as following:
|
43
|
+
|
44
|
+
$ bacon spec/ses/*.rb
|
45
|
+
|
46
|
+
## License
|
47
|
+
|
48
|
+
The code in this repository is licensed under the MIT license. A copy of this
|
49
|
+
license can be found in the file "LICENSE".
|
data/Rakefile
ADDED
data/lib/.gitkeep
ADDED
File without changes
|
data/lib/ses.rb
ADDED
data/lib/ses/.gitkeep
ADDED
File without changes
|
data/lib/ses/client.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'openssl'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module SES
|
6
|
+
##
|
7
|
+
# Client for sending HTTP requests to the Amazon SES API using HTTParty.
|
8
|
+
#
|
9
|
+
# In order to be able to send Emails you'll have to specify an access key and
|
10
|
+
# a secret key. These keys can be set as following:
|
11
|
+
#
|
12
|
+
# SES::Client::OPTIONS[:access_key] = '...'
|
13
|
+
# SES::Client::OPTIONS[:secret_key] = '...'
|
14
|
+
#
|
15
|
+
# Once set you can start sending Emails using {SES::Email}.
|
16
|
+
#
|
17
|
+
# @since 24-01-2012
|
18
|
+
#
|
19
|
+
module Client
|
20
|
+
include HTTParty
|
21
|
+
|
22
|
+
format :xml
|
23
|
+
base_uri 'https://email.us-east-1.amazonaws.com'
|
24
|
+
|
25
|
+
# Hash containing the configuration options required for each HTTP
|
26
|
+
# request.
|
27
|
+
OPTIONS = {
|
28
|
+
# Your AWS access key.
|
29
|
+
:access_key => nil,
|
30
|
+
|
31
|
+
# Your AWS secret key.
|
32
|
+
:secret_key => nil,
|
33
|
+
|
34
|
+
# The version of the SES API.
|
35
|
+
:version => '2010-12-01'
|
36
|
+
}
|
37
|
+
|
38
|
+
class << self
|
39
|
+
##
|
40
|
+
# Executes a signed POST request.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# response = SES::Client.signed_post(
|
44
|
+
# :Action => 'SendEmail',
|
45
|
+
# :source => 'foo@bar.com',
|
46
|
+
# ...
|
47
|
+
# )
|
48
|
+
#
|
49
|
+
# puts response.parsed_response
|
50
|
+
#
|
51
|
+
# @since 24-01-2012
|
52
|
+
# @param [String] uri The URI relative to the base URL to send the request
|
53
|
+
# to.
|
54
|
+
# @param [Hash] body A hash containing the various keys and values that
|
55
|
+
# have to used as POST fields.
|
56
|
+
# @return [Mixed]
|
57
|
+
#
|
58
|
+
def signed_post(uri = '/', body = {})
|
59
|
+
verify_keys
|
60
|
+
|
61
|
+
time = Time.now
|
62
|
+
url_time = time.strftime('%Y-%m-%dT%H:%M:%S.000Z')
|
63
|
+
sig_time = time.gmtime.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
64
|
+
|
65
|
+
body[:Timestamp] = url_time
|
66
|
+
body[:Version] = OPTIONS[:version]
|
67
|
+
body[:AWSAccessKeyId] = OPTIONS[:access_key]
|
68
|
+
|
69
|
+
data = {
|
70
|
+
:headers => {
|
71
|
+
'X-Amzn-Authorization' => signature(sig_time),
|
72
|
+
'Date' => sig_time
|
73
|
+
},
|
74
|
+
:body => body
|
75
|
+
}
|
76
|
+
|
77
|
+
return post(uri, data)
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Checks if the AWS access and secret key are set and raises an error if
|
82
|
+
# this isn't the case.
|
83
|
+
#
|
84
|
+
# @since 24-01-2012
|
85
|
+
# @raise [SES::Error] raised whenever one of the keys was
|
86
|
+
# missing.
|
87
|
+
#
|
88
|
+
def verify_keys
|
89
|
+
[:access_key, :secret_key].each do |k|
|
90
|
+
if OPTIONS[k].nil? or OPTIONS[k].empty?
|
91
|
+
raise(
|
92
|
+
SES::Error,
|
93
|
+
"You have to specify a non empty value for the #{k} option" \
|
94
|
+
" in SES::Client::OPTIONS"
|
95
|
+
)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# Generates a signature to use for a single HTTP request.
|
102
|
+
#
|
103
|
+
# @since 24-01-2012
|
104
|
+
# @param [String] time The signature time as a string in the format
|
105
|
+
# ``%a, %d %b %Y %H:%M:%S GMT``.
|
106
|
+
# @return [String]
|
107
|
+
#
|
108
|
+
def signature(time)
|
109
|
+
hash = OpenSSL::HMAC.digest(
|
110
|
+
OpenSSL::Digest::Digest.new('sha256'),
|
111
|
+
OPTIONS[:secret_key],
|
112
|
+
time
|
113
|
+
)
|
114
|
+
|
115
|
+
hash = Base64.encode64(hash).chomp
|
116
|
+
|
117
|
+
return "AWS3-HTTPS AWSAccessKey=#{OPTIONS[:access_key]}, " \
|
118
|
+
"Signature=#{hash}, Algorithm=HmacSHA256"
|
119
|
+
end
|
120
|
+
end # class << self
|
121
|
+
end # Client
|
122
|
+
end # SES
|
data/lib/ses/email.rb
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
module SES
|
2
|
+
##
|
3
|
+
# Class used for creating and sending Emails.
|
4
|
+
#
|
5
|
+
# In order to create a new Email you call {SES::Email.new} and provide a hash
|
6
|
+
# containing parameters such as the sender's Email, subject, etc:
|
7
|
+
#
|
8
|
+
# mail = SES::Email.new(
|
9
|
+
# :from => 'user@example.com',
|
10
|
+
# :to => 'anotheruser@example.com',
|
11
|
+
# :subject => 'Testing',
|
12
|
+
# :body => 'This is the Email body.'
|
13
|
+
# )
|
14
|
+
#
|
15
|
+
# Once the mail object has been created you can send it by calling
|
16
|
+
# {SES::Email#deliver}:
|
17
|
+
#
|
18
|
+
# mail.deliver
|
19
|
+
#
|
20
|
+
# Upon success the return value is set to the message ID of the newly created
|
21
|
+
# Email, upon any failure an instance of {SES::Error} is raised so be sure to
|
22
|
+
# properly wrap calls to {SES::Email#deliver} in a begin/rescue block:
|
23
|
+
#
|
24
|
+
# begin
|
25
|
+
# mail.deliver
|
26
|
+
# rescue SES::Error => e
|
27
|
+
# # Do something with the error.
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# ## Default Sender Details
|
31
|
+
#
|
32
|
+
# To make it easier to send Emails you can set the default sender Email and
|
33
|
+
# name in the hash {SES::Email::OPTIONS}. These options can be set as
|
34
|
+
# following:
|
35
|
+
#
|
36
|
+
# SES::Email::OPTIONS[:sender] = 'user@example.com'
|
37
|
+
# SES::Email::OPTIONS[:sender_name] = 'User'
|
38
|
+
#
|
39
|
+
# Once set these values will be used whenever there are no custom values
|
40
|
+
# specified for the sender Email/name.
|
41
|
+
#
|
42
|
+
# @since 24-01-2012
|
43
|
+
#
|
44
|
+
class Email
|
45
|
+
# Hash containing various configuration options.
|
46
|
+
OPTIONS = {
|
47
|
+
# The default sender Email to use.
|
48
|
+
:sender => '',
|
49
|
+
|
50
|
+
# The default name of the sender.
|
51
|
+
:sender_name => ''
|
52
|
+
}
|
53
|
+
|
54
|
+
# The Email address of the sender.
|
55
|
+
attr_accessor :from
|
56
|
+
|
57
|
+
# The full name of the sender.
|
58
|
+
attr_accessor :name
|
59
|
+
|
60
|
+
# A list of addresses to send the Email to. If a string is given the Email
|
61
|
+
# is only sent to that particular address, if an array is given the Email
|
62
|
+
# will be sent to all the specified addresses.
|
63
|
+
attr_accessor :to
|
64
|
+
|
65
|
+
# String containing the subject of the Email.
|
66
|
+
attr_accessor :subject
|
67
|
+
|
68
|
+
# String containing the body of the Email.
|
69
|
+
attr_accessor :body
|
70
|
+
|
71
|
+
# When set to true the Email will be sent as an HTML email. Set to
|
72
|
+
# ``false`` by default.
|
73
|
+
attr_accessor :html
|
74
|
+
|
75
|
+
# The character set to use for the subject and body. The character set is
|
76
|
+
# set to UTF-8 by default.
|
77
|
+
attr_accessor :charset
|
78
|
+
|
79
|
+
##
|
80
|
+
# Creates a new instance of the class and sets the specified attributes
|
81
|
+
# such as the sender's Email and subject.
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
# email = SES::Email.new(
|
85
|
+
# :from => 'user@example.com',
|
86
|
+
# :name => 'Example User',
|
87
|
+
# :to => 'another_user@example.com',
|
88
|
+
# :subject => 'Testing',
|
89
|
+
# :body => 'This is a test Email.'
|
90
|
+
# )
|
91
|
+
#
|
92
|
+
# @since 24-01-2012
|
93
|
+
# @param [Hash] options A hash containing the attributes to set. See the
|
94
|
+
# corresponding getters/setters for their descriptions.
|
95
|
+
# @option options [String] :from The Email of the sender.
|
96
|
+
# @option options [String] :name The name of the sender.
|
97
|
+
# @option options [String|Array] :to A string containing a single Email
|
98
|
+
# address to send the Email to or an array of multiple Email addresses.
|
99
|
+
# @option options [String] :subject The subject of the Email.
|
100
|
+
# @option options [String] :body The body of the Email.
|
101
|
+
# @option options [String] :html When set to ``true`` the Email will be
|
102
|
+
# sent as an HTML Email.
|
103
|
+
# @option options [String] :charset The character set to use for the Email,
|
104
|
+
# set to UTF-8 by default.
|
105
|
+
#
|
106
|
+
def initialize(options = {})
|
107
|
+
@from = options[:from] || OPTIONS[:sender]
|
108
|
+
@name = options[:name] || OPTIONS[:sender_name]
|
109
|
+
@to = options[:to]
|
110
|
+
@subject = options[:subject]
|
111
|
+
@body = options[:body]
|
112
|
+
@html = options[:html] || false
|
113
|
+
@charset = options[:charset] || 'UTF-8'
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Sends the Email and returns the message ID.
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# email = SES::Email.new(...)
|
121
|
+
# id = email.deliver
|
122
|
+
#
|
123
|
+
# puts id # => "0000013511a87590-......."
|
124
|
+
#
|
125
|
+
# @since 24-01-2012
|
126
|
+
# @return [String]
|
127
|
+
# @raise [SES::Error] Raised whenever the Email could not be
|
128
|
+
# sent.
|
129
|
+
#
|
130
|
+
def deliver
|
131
|
+
validate
|
132
|
+
|
133
|
+
if @name.nil?
|
134
|
+
from = @from
|
135
|
+
else
|
136
|
+
from = "#{@name} <#{@from}>"
|
137
|
+
end
|
138
|
+
|
139
|
+
options = {
|
140
|
+
:Action => 'SendEmail',
|
141
|
+
:Source => from,
|
142
|
+
:'Message.Subject.Data' => @subject,
|
143
|
+
:'Message.Subject.Charset' => @charset
|
144
|
+
}
|
145
|
+
|
146
|
+
if @html == true
|
147
|
+
options[:'Message.Body.Html.Data'] = @body
|
148
|
+
options[:'Message.Body.Html.Charset'] = @charset
|
149
|
+
else
|
150
|
+
options[:'Message.Body.Text.Data'] = @body
|
151
|
+
options[:'Message.Body.Text.Charset'] = @charset
|
152
|
+
end
|
153
|
+
|
154
|
+
if @to.is_a?(Array)
|
155
|
+
num = 1
|
156
|
+
|
157
|
+
@to.each do |value, index|
|
158
|
+
if !value.nil? and !value.empty?
|
159
|
+
options[:"Destination.toAddresses.member.#{num}"] = value
|
160
|
+
|
161
|
+
num += 1
|
162
|
+
end
|
163
|
+
end
|
164
|
+
else
|
165
|
+
options[:'Destination.ToAddresses.member.1'] = @to
|
166
|
+
end
|
167
|
+
|
168
|
+
response = SES::Client.signed_post('/', options)
|
169
|
+
parsed = response.parsed_response
|
170
|
+
|
171
|
+
# Bummer, something went wrong.
|
172
|
+
if response.code != 200 and parsed.key?('ErrorResponse')
|
173
|
+
message = parsed['ErrorResponse']['Error']['Message']
|
174
|
+
|
175
|
+
raise(SES::Error, "Failed to send the Email: #{message}")
|
176
|
+
|
177
|
+
# Everything is fine, get the mail ID.
|
178
|
+
elsif response.code == 200 and parsed.key?('SendEmailResponse')
|
179
|
+
return parsed['SendEmailResponse']['SendEmailResult']['MessageId']
|
180
|
+
|
181
|
+
else
|
182
|
+
raise(
|
183
|
+
SES::Error,
|
184
|
+
"Failed to extract the message ID, raw response: #{response.body}"
|
185
|
+
)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# Validates the attributes (such as the name and subject) and raises an
|
191
|
+
# error if they're invalid.
|
192
|
+
#
|
193
|
+
# @since 24-01-2012
|
194
|
+
# @raise [SES::ValidationError] raised whenever one of the set
|
195
|
+
# attributes is invalid.
|
196
|
+
#
|
197
|
+
def validate
|
198
|
+
if @from.nil? or @from.empty?
|
199
|
+
raise(
|
200
|
+
SES::ValidationError,
|
201
|
+
'You have to specify the from address'
|
202
|
+
)
|
203
|
+
end
|
204
|
+
|
205
|
+
if !@to.is_a?(Array) and !@to.is_a?(String)
|
206
|
+
raise(
|
207
|
+
SES::ValidationError,
|
208
|
+
"Expected an instance of Array or String for the to address but " \
|
209
|
+
"got #{@to.class} instead"
|
210
|
+
)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end # Email
|
214
|
+
end # SES
|
data/lib/ses/errors.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module SES
|
2
|
+
##
|
3
|
+
# Generic error class for the Amazon SES package.
|
4
|
+
#
|
5
|
+
# @since 24-01-2012
|
6
|
+
#
|
7
|
+
class Error < ::StandardError; end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Error class used by {SES::Email#validate}.
|
11
|
+
#
|
12
|
+
# @since 24-01-2012
|
13
|
+
#
|
14
|
+
class ValidationError < ::StandardError; end
|
15
|
+
end # SES
|
data/lib/ses/version.rb
ADDED
data/pkg/.gitkeep
ADDED
File without changes
|
data/ses.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path('../lib/ses/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'ses'
|
5
|
+
s.version = SES::VERSION
|
6
|
+
s.date = '2012-03-09'
|
7
|
+
s.authors = ['Yorick Peterse']
|
8
|
+
s.email = 'yorickpeterse@gmail.com'
|
9
|
+
s.summary = 'A small and easy to use Gem for Amazon SES.'
|
10
|
+
s.homepage = 'https://github.com/yorickpeterse/ses'
|
11
|
+
s.description = s.summary
|
12
|
+
s.files = `git ls-files`.split("\n").sort
|
13
|
+
s.has_rdoc = 'yard'
|
14
|
+
|
15
|
+
s.add_dependency 'httparty', ['>= 0.8.1']
|
16
|
+
|
17
|
+
s.add_development_dependency 'rake' , ['>= 0.9.2']
|
18
|
+
s.add_development_dependency 'yard' , ['>= 0.7.2']
|
19
|
+
s.add_development_dependency 'bacon', ['>= 1.1.0']
|
20
|
+
s.add_development_dependency 'rdiscount', ['>= 1.6.8']
|
21
|
+
end
|
data/spec/.gitkeep
ADDED
File without changes
|
data/spec/helper.rb
ADDED
data/spec/ses/client.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path('../../helper', __FILE__)
|
2
|
+
|
3
|
+
describe 'SES::Client' do
|
4
|
+
after do
|
5
|
+
SES::Client::OPTIONS[:access_key] = nil
|
6
|
+
SES::Client::OPTIONS[:secret_key] = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'Verify the access and secret keys' do
|
10
|
+
should.raise SES::Error do
|
11
|
+
SES::Client.verify_keys
|
12
|
+
end
|
13
|
+
|
14
|
+
SES::Client::OPTIONS[:access_key] = 'access'
|
15
|
+
|
16
|
+
should.raise SES::Error do
|
17
|
+
SES::Client.verify_keys
|
18
|
+
end
|
19
|
+
|
20
|
+
SES::Client::OPTIONS[:secret_key] = 'secret'
|
21
|
+
|
22
|
+
should.not.raise SES::Error do
|
23
|
+
SES::Client.verify_keys
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'Generate a signature for a given time' do
|
28
|
+
SES::Client::OPTIONS[:access_key] = 'access'
|
29
|
+
SES::Client::OPTIONS[:secret_key] = 'secret'
|
30
|
+
|
31
|
+
time = Time.new.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
32
|
+
hash = OpenSSL::HMAC.digest(
|
33
|
+
OpenSSL::Digest::Digest.new('sha256'),
|
34
|
+
'secret',
|
35
|
+
time
|
36
|
+
)
|
37
|
+
|
38
|
+
hash = Base64.encode64(hash).chomp
|
39
|
+
got = SES::Client.signature(time)
|
40
|
+
|
41
|
+
got.should == "AWS3-HTTPS AWSAccessKey=access, Signature=#{hash}, " \
|
42
|
+
"Algorithm=HmacSHA256"
|
43
|
+
end
|
44
|
+
end
|
data/spec/ses/email.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
require File.expand_path('../../helper', __FILE__)
|
2
|
+
|
3
|
+
describe 'SES::Email' do
|
4
|
+
extend WebMock::API
|
5
|
+
|
6
|
+
after do
|
7
|
+
SES::Email::OPTIONS[:sender] = nil
|
8
|
+
SES::Email::OPTIONS[:sender_name] = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'Create a new instance of SES::Email and set the various parameters' do
|
12
|
+
email = SES::Email.new(
|
13
|
+
:from => 'user@example.com',
|
14
|
+
:name => 'User',
|
15
|
+
:to => 'user1@example.com',
|
16
|
+
:subject => 'Example',
|
17
|
+
:body => 'This is the body',
|
18
|
+
:html => true
|
19
|
+
)
|
20
|
+
|
21
|
+
email.from.should == 'user@example.com'
|
22
|
+
email.name.should == 'User'
|
23
|
+
email.to.should == 'user1@example.com'
|
24
|
+
email.subject.should == 'Example'
|
25
|
+
email.body.should == 'This is the body'
|
26
|
+
email.html.should == true
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'Use the default sender and sender name if these are not manually given' do
|
30
|
+
SES::Email::OPTIONS[:sender] = 'user@example.com'
|
31
|
+
SES::Email::OPTIONS[:sender_name] = 'User'
|
32
|
+
|
33
|
+
email = SES::Email.new(
|
34
|
+
:to => 'user1@example.com',
|
35
|
+
:subject => 'Example',
|
36
|
+
:body => 'This is the body',
|
37
|
+
:html => true
|
38
|
+
)
|
39
|
+
|
40
|
+
email.from.should == 'user@example.com'
|
41
|
+
email.name.should == 'User'
|
42
|
+
email.to.should == 'user1@example.com'
|
43
|
+
email.subject.should == 'Example'
|
44
|
+
email.body.should == 'This is the body'
|
45
|
+
email.html.should == true
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'Raise when no sender Email is specified' do
|
49
|
+
should.raise SES::ValidationError do
|
50
|
+
SES::Email.new.deliver
|
51
|
+
end
|
52
|
+
|
53
|
+
should.raise SES::ValidationError do
|
54
|
+
SES::Email.new(:from => 'foo@bar.com').deliver
|
55
|
+
end
|
56
|
+
|
57
|
+
# :to can only be an array or a string.
|
58
|
+
should.raise SES::ValidationError do
|
59
|
+
SES::Email.new(:from => 'foo@bar.com', :to => 10).deliver
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'Send a valid Email' do
|
64
|
+
SES::Client::OPTIONS[:access_key] = 'access'
|
65
|
+
SES::Client::OPTIONS[:secret_key] = 'secret'
|
66
|
+
|
67
|
+
email = SES::Email.new(
|
68
|
+
:from => 'user@example.com',
|
69
|
+
:name => 'User',
|
70
|
+
:to => 'user1@example.com',
|
71
|
+
:subject => 'Example',
|
72
|
+
:body => 'This is the body',
|
73
|
+
:html => true
|
74
|
+
)
|
75
|
+
|
76
|
+
message_id = '00000131d51d2292-159ad6eb-077c-46e6-ad09-ae7c05925ed4-000000'
|
77
|
+
response_body = <<-XML.strip
|
78
|
+
<SendEmailResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
79
|
+
<SendEmailResult>
|
80
|
+
<MessageId>#{message_id}</MessageId>
|
81
|
+
</SendEmailResult>
|
82
|
+
<ResponseMetadata>
|
83
|
+
<RequestId>d5964849-c866-11e0-9beb-01a62d68c57f</RequestId>
|
84
|
+
</ResponseMetadata>
|
85
|
+
</SendEmailResponse>
|
86
|
+
XML
|
87
|
+
|
88
|
+
stub_request(:post, 'https://email.us-east-1.amazonaws.com') \
|
89
|
+
.to_return(:status => 200, :body => response_body)
|
90
|
+
|
91
|
+
email.deliver.should == message_id
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'Send an invalid Email' do
|
95
|
+
SES::Client::OPTIONS[:access_key] = 'access'
|
96
|
+
SES::Client::OPTIONS[:secret_key] = 'secret'
|
97
|
+
|
98
|
+
email = SES::Email.new(
|
99
|
+
:from => 'user@example.com',
|
100
|
+
:name => 'User',
|
101
|
+
:to => 'user1@example.com',
|
102
|
+
:subject => 'Example',
|
103
|
+
:body => 'This is the body',
|
104
|
+
:html => true
|
105
|
+
)
|
106
|
+
|
107
|
+
response_body = <<-XML.strip
|
108
|
+
<ErrorResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
109
|
+
<Error>
|
110
|
+
<Message>Something went wrong</Message>
|
111
|
+
</Error>
|
112
|
+
</ErrorResponse>
|
113
|
+
XML
|
114
|
+
|
115
|
+
stub_request(:post, 'https://email.us-east-1.amazonaws.com') \
|
116
|
+
.to_return(:status => 400, :body => response_body)
|
117
|
+
|
118
|
+
should.raise SES::Error do
|
119
|
+
email.deliver
|
120
|
+
end
|
121
|
+
|
122
|
+
begin
|
123
|
+
email.deliver
|
124
|
+
rescue => e
|
125
|
+
e.message.should == 'Failed to send the Email: Something went wrong'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/task/build.rake
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
namespace :build do
|
2
|
+
desc 'Builds a new Gem'
|
3
|
+
task :gem do
|
4
|
+
gemspec = Gem::Specification.load(
|
5
|
+
File.expand_path('../../ses.gemspec', __FILE__)
|
6
|
+
)
|
7
|
+
|
8
|
+
root = File.expand_path('../../', __FILE__)
|
9
|
+
name = "#{gemspec.name}-#{gemspec.version.version}.gem"
|
10
|
+
path = File.join(root, name)
|
11
|
+
pkg = File.join(root, 'pkg', name)
|
12
|
+
|
13
|
+
# Build and install the gem
|
14
|
+
sh('gem', 'build', File.join(root, 'ses.gemspec'))
|
15
|
+
sh('mv' , path, pkg)
|
16
|
+
sh('gem', 'install', pkg)
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ses
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Yorick Peterse
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: httparty
|
16
|
+
requirement: &2152150100 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.8.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2152150100
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &2152148320 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.9.2
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2152148320
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: yard
|
38
|
+
requirement: &2152145140 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.7.2
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2152145140
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bacon
|
49
|
+
requirement: &2152156200 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.1.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2152156200
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rdiscount
|
60
|
+
requirement: &2152155140 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.6.8
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2152155140
|
69
|
+
description: A small and easy to use Gem for Amazon SES.
|
70
|
+
email: yorickpeterse@gmail.com
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- .gems
|
76
|
+
- .gitignore
|
77
|
+
- .rvmrc
|
78
|
+
- .travis.yml
|
79
|
+
- .yardopts
|
80
|
+
- LICENSE
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- lib/.gitkeep
|
84
|
+
- lib/ses.rb
|
85
|
+
- lib/ses/.gitkeep
|
86
|
+
- lib/ses/client.rb
|
87
|
+
- lib/ses/email.rb
|
88
|
+
- lib/ses/errors.rb
|
89
|
+
- lib/ses/version.rb
|
90
|
+
- pkg/.gitkeep
|
91
|
+
- ses.gemspec
|
92
|
+
- spec/.gitkeep
|
93
|
+
- spec/helper.rb
|
94
|
+
- spec/ses/client.rb
|
95
|
+
- spec/ses/email.rb
|
96
|
+
- task/build.rake
|
97
|
+
homepage: https://github.com/yorickpeterse/ses
|
98
|
+
licenses: []
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 1.8.16
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: A small and easy to use Gem for Amazon SES.
|
121
|
+
test_files: []
|
122
|
+
has_rdoc: yard
|