axtro-aws-ses 0.4.4

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.
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ * Use a better XML parser (and be consistent)
2
+ * Rename Base to something else (probably Mailer): Nothing else actually inherits from Base, so that is a very poor naming convention. I intend to change it in the future
3
+ * Integer responses should probably be cast to ints instead of left as strings
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.4
@@ -0,0 +1,102 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{aws-ses}
8
+ s.version = "0.4.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Drew Blas", "Marcel Molina Jr."]
12
+ s.date = %q{2011-06-23}
13
+ s.description = %q{Client library for Amazon's Simple Email Service's REST API}
14
+ s.email = %q{drew.blas@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.erb",
18
+ "README.rdoc",
19
+ "TODO"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ "CHANGELOG",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE",
27
+ "README.erb",
28
+ "README.rdoc",
29
+ "Rakefile",
30
+ "TODO",
31
+ "VERSION",
32
+ "aws-ses.gemspec",
33
+ "lib/aws/actionmailer/ses_extension.rb",
34
+ "lib/aws/ses.rb",
35
+ "lib/aws/ses/addresses.rb",
36
+ "lib/aws/ses/base.rb",
37
+ "lib/aws/ses/extensions.rb",
38
+ "lib/aws/ses/info.rb",
39
+ "lib/aws/ses/response.rb",
40
+ "lib/aws/ses/send_email.rb",
41
+ "lib/aws/ses/version.rb",
42
+ "test/address_test.rb",
43
+ "test/base_test.rb",
44
+ "test/extensions_test.rb",
45
+ "test/fixtures.rb",
46
+ "test/helper.rb",
47
+ "test/info_test.rb",
48
+ "test/mocks/fake_response.rb",
49
+ "test/response_test.rb",
50
+ "test/send_email_test.rb"
51
+ ]
52
+ s.homepage = %q{http://github.com/drewblas/aws-ses}
53
+ s.licenses = ["MIT"]
54
+ s.require_paths = ["lib"]
55
+ s.rubygems_version = %q{1.5.2}
56
+ s.summary = %q{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
+ ]
68
+
69
+ if s.respond_to? :specification_version then
70
+ s.specification_version = 3
71
+
72
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
73
+ s.add_runtime_dependency(%q<xml-simple>, [">= 0"])
74
+ s.add_runtime_dependency(%q<builder>, [">= 0"])
75
+ s.add_runtime_dependency(%q<mime-types>, [">= 0"])
76
+ s.add_development_dependency(%q<shoulda-context>, [">= 0"])
77
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
78
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
79
+ s.add_development_dependency(%q<rcov>, [">= 0"])
80
+ s.add_development_dependency(%q<flexmock>, ["~> 0.8.11"])
81
+ else
82
+ s.add_dependency(%q<xml-simple>, [">= 0"])
83
+ s.add_dependency(%q<builder>, [">= 0"])
84
+ s.add_dependency(%q<mime-types>, [">= 0"])
85
+ s.add_dependency(%q<shoulda-context>, [">= 0"])
86
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
87
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
88
+ s.add_dependency(%q<rcov>, [">= 0"])
89
+ s.add_dependency(%q<flexmock>, ["~> 0.8.11"])
90
+ end
91
+ else
92
+ s.add_dependency(%q<xml-simple>, [">= 0"])
93
+ s.add_dependency(%q<builder>, [">= 0"])
94
+ s.add_dependency(%q<mime-types>, [">= 0"])
95
+ s.add_dependency(%q<shoulda-context>, [">= 0"])
96
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
97
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
98
+ s.add_dependency(%q<rcov>, [">= 0"])
99
+ s.add_dependency(%q<flexmock>, ["~> 0.8.11"])
100
+ end
101
+ end
102
+
@@ -0,0 +1,104 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{axtro-aws-ses}
8
+ s.version = "0.4.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Drew Blas", "Marcel Molina Jr."]
12
+ s.date = %q{2011-10-31}
13
+ s.description = %q{Client library for Amazon's Simple Email Service's REST API}
14
+ s.email = %q{drew.blas@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.erb",
18
+ "README.rdoc",
19
+ "TODO"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ "CHANGELOG",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE",
27
+ "README.erb",
28
+ "README.rdoc",
29
+ "Rakefile",
30
+ "TODO",
31
+ "VERSION",
32
+ "aws-ses.gemspec",
33
+ "axtro-aws-ses.gemspec",
34
+ "lib/aws/actionmailer/ses_extension.rb",
35
+ "lib/aws/ses.rb",
36
+ "lib/aws/ses/addresses.rb",
37
+ "lib/aws/ses/base.rb",
38
+ "lib/aws/ses/expirable_memoize.rb",
39
+ "lib/aws/ses/info.rb",
40
+ "lib/aws/ses/response.rb",
41
+ "lib/aws/ses/send_email.rb",
42
+ "lib/aws/ses/version.rb",
43
+ "test/address_test.rb",
44
+ "test/base_test.rb",
45
+ "test/expirable_memoize_test.rb",
46
+ "test/fixtures.rb",
47
+ "test/helper.rb",
48
+ "test/info_test.rb",
49
+ "test/mocks/fake_response.rb",
50
+ "test/response_test.rb",
51
+ "test/send_email_test.rb"
52
+ ]
53
+ s.homepage = %q{http://github.com/axtro/aws-ses}
54
+ s.licenses = ["MIT"]
55
+ s.require_paths = ["lib"]
56
+ s.rubygems_version = %q{1.3.7}
57
+ s.summary = %q{Client library for Amazon's Simple Email Service's REST API}
58
+ s.test_files = [
59
+ "test/address_test.rb",
60
+ "test/base_test.rb",
61
+ "test/expirable_memoize_test.rb",
62
+ "test/fixtures.rb",
63
+ "test/helper.rb",
64
+ "test/info_test.rb",
65
+ "test/mocks/fake_response.rb",
66
+ "test/response_test.rb",
67
+ "test/send_email_test.rb"
68
+ ]
69
+
70
+ if s.respond_to? :specification_version then
71
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
72
+ s.specification_version = 3
73
+
74
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
75
+ s.add_runtime_dependency(%q<xml-simple>, [">= 0"])
76
+ s.add_runtime_dependency(%q<builder>, [">= 0"])
77
+ s.add_runtime_dependency(%q<mime-types>, [">= 0"])
78
+ s.add_development_dependency(%q<shoulda-context>, [">= 0"])
79
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
80
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
81
+ s.add_development_dependency(%q<rcov>, [">= 0"])
82
+ s.add_development_dependency(%q<flexmock>, ["~> 0.8.11"])
83
+ else
84
+ s.add_dependency(%q<xml-simple>, [">= 0"])
85
+ s.add_dependency(%q<builder>, [">= 0"])
86
+ s.add_dependency(%q<mime-types>, [">= 0"])
87
+ s.add_dependency(%q<shoulda-context>, [">= 0"])
88
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
89
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
90
+ s.add_dependency(%q<rcov>, [">= 0"])
91
+ s.add_dependency(%q<flexmock>, ["~> 0.8.11"])
92
+ end
93
+ else
94
+ s.add_dependency(%q<xml-simple>, [">= 0"])
95
+ s.add_dependency(%q<builder>, [">= 0"])
96
+ s.add_dependency(%q<mime-types>, [">= 0"])
97
+ s.add_dependency(%q<shoulda-context>, [">= 0"])
98
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
99
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
100
+ s.add_dependency(%q<rcov>, [">= 0"])
101
+ s.add_dependency(%q<flexmock>, ["~> 0.8.11"])
102
+ end
103
+ end
104
+
@@ -0,0 +1,19 @@
1
+ # A quick little extension to use this lib with with rails 2.3.X
2
+ # To use it, in your environment.rb or some_environment.rb you simply set
3
+ #
4
+ # config.after_initialize do
5
+ # ActionMailer::Base.delivery_method = :amazon_ses
6
+ # ActionMailer::Base.custom_amazon_ses_mailer = AWS::SES::Base.new(:secret_access_key => S3_CONFIG[:secret_access_key], :access_key_id => S3_CONFIG[:access_key_id])
7
+ # end
8
+
9
+ module ActionMailer
10
+ class Base
11
+ cattr_accessor :custom_amazon_ses_mailer
12
+
13
+ def perform_delivery_amazon_ses(mail)
14
+ raise 'AWS::SES::Base has not been intitialized.' unless @@custom_amazon_ses_mailer
15
+ @@custom_amazon_ses_mailer.deliver!(mail)
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ %w[ base64 cgi openssl digest/sha1 net/https net/http rexml/document time ostruct].each { |f| require f }
2
+
3
+ begin
4
+ require 'URI' unless defined? URI
5
+ rescue Exception => e
6
+ # nothing
7
+ end
8
+
9
+ begin
10
+ require 'xmlsimple' unless defined? XmlSimple
11
+ rescue Exception => e
12
+ require 'xml-simple' unless defined? XmlSimple
13
+ end
14
+
15
+ $:.unshift(File.dirname(__FILE__))
16
+
17
+ require 'ses/expirable_memoize'
18
+
19
+ require 'ses/response'
20
+ require 'ses/send_email'
21
+ require 'ses/info'
22
+ require 'ses/base'
23
+ require 'ses/version'
24
+ require 'ses/addresses'
25
+
26
+ if defined?(Rails)
27
+ major, minor = Rails.version.split('.')
28
+ require 'actionmailer/ses_extension' if major == '2' && minor == '3'
29
+ end
@@ -0,0 +1,75 @@
1
+ module AWS
2
+ module SES
3
+ # AWS::SES::Addresses provides for:
4
+ # * Listing verified e-mail addresses
5
+ # * Adding new e-mail addresses to verify
6
+ # * Deleting verified e-mail addresses
7
+ #
8
+ # You can access these methods as follows:
9
+ #
10
+ # ses = AWS::SES::Base.new( ... connection info ... )
11
+ #
12
+ # # Get a list of verified addresses
13
+ # ses.addresses.list.result
14
+ #
15
+ # # Add a new e-mail address to verify
16
+ # ses.addresses.verify('jon@example.com')
17
+ #
18
+ # # Delete an e-mail address
19
+ # ses.addresses.delete('jon@example.com')
20
+ class Addresses < Base
21
+ def initialize(ses)
22
+ @ses = ses
23
+ end
24
+
25
+ # List all verified e-mail addresses
26
+ #
27
+ # Usage:
28
+ # ses.addresses.list.result
29
+ # =>
30
+ # ['email1@example.com', email2@example.com']
31
+ def list
32
+ @ses.request('ListVerifiedEmailAddresses')
33
+ end
34
+
35
+ def verify(email)
36
+ @ses.request('VerifyEmailAddress',
37
+ 'EmailAddress' => email
38
+ )
39
+ end
40
+
41
+ def delete(email)
42
+ @ses.request('DeleteVerifiedEmailAddress',
43
+ 'EmailAddress' => email
44
+ )
45
+ end
46
+ end
47
+
48
+ class ListVerifiedEmailAddressesResponse < AWS::SES::Response
49
+ def result
50
+ if members = parsed['ListVerifiedEmailAddressesResult']['VerifiedEmailAddresses']
51
+ [members['member']].flatten
52
+ else
53
+ []
54
+ end
55
+ end
56
+ memoized :result
57
+ end
58
+
59
+ class VerifyEmailAddressResponse < AWS::SES::Response
60
+ end
61
+
62
+ class DeleteVerifiedEmailAddressResponse < AWS::SES::Response
63
+ def result
64
+ success?
65
+ end
66
+ end
67
+
68
+ class Base
69
+ def addresses
70
+ @addresses ||= Addresses.new(self)
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,176 @@
1
+ module AWS #:nodoc:
2
+ # AWS::SES is a Ruby library for Amazon's Simple Email Service's REST API (http://aws.amazon.com/ses).
3
+ #
4
+ # == Getting started
5
+ #
6
+ # To get started you need to require 'aws/ses':
7
+ #
8
+ # % irb -rubygems
9
+ # irb(main):001:0> require 'aws/ses'
10
+ # # => true
11
+ #
12
+ # Before you can do anything, you must establish a connection using Base.new. A basic connection would look something like this:
13
+ #
14
+ # ses = AWS::SES::Base.new(
15
+ # :access_key_id => 'abc',
16
+ # :secret_access_key => '123'
17
+ # )
18
+ #
19
+ # The minimum connection options that you must specify are your access key id and your secret access key.
20
+ module SES
21
+
22
+ API_VERSION = '2010-12-01'
23
+
24
+ DEFAULT_HOST = 'email.us-east-1.amazonaws.com'
25
+
26
+ USER_AGENT = 'github-aws-ses-ruby-gem'
27
+
28
+ # Encodes the given string with the secret_access_key by taking the
29
+ # hmac-sha1 sum, and then base64 encoding it. Optionally, it will also
30
+ # url encode the result of that to protect the string if it's going to
31
+ # be used as a query string parameter.
32
+ #
33
+ # @param [String] secret_access_key the user's secret access key for signing.
34
+ # @param [String] str the string to be hashed and encoded.
35
+ # @param [Boolean] urlencode whether or not to url encode the result., true or false
36
+ # @return [String] the signed and encoded string.
37
+ def SES.encode(secret_access_key, str, urlencode=true)
38
+ digest = OpenSSL::Digest::Digest.new('sha256')
39
+ b64_hmac =
40
+ Base64.encode64(
41
+ OpenSSL::HMAC.digest(digest, secret_access_key, str)).gsub("\n","")
42
+
43
+ if urlencode
44
+ return CGI::escape(b64_hmac)
45
+ else
46
+ return b64_hmac
47
+ end
48
+ end
49
+
50
+ # Generates the HTTP Header String that Amazon looks for
51
+ #
52
+ # @param [String] key the AWS Access Key ID
53
+ # @param [String] alg the algorithm used for the signature
54
+ # @param [String] sig the signature itself
55
+ def SES.authorization_header(key, alg, sig)
56
+ "AWS3-HTTPS AWSAccessKeyId=#{key}, Algorithm=#{alg}, Signature=#{sig}"
57
+ end
58
+
59
+ # AWS::SES::Base is the abstract super class of all classes who make requests against SES
60
+ class Base
61
+ include SendEmail
62
+ include Info
63
+
64
+ attr_reader :use_ssl, :server, :proxy_server, :port
65
+
66
+ # @option options [String] :access_key_id ("") The user's AWS Access Key ID
67
+ # @option options [String] :secret_access_key ("") The user's AWS Secret Access Key
68
+ # @option options [Boolean] :use_ssl (true) Connect using SSL?
69
+ # @option options [String] :server ("email.us-east-1.amazonaws.com") The server API endpoint host
70
+ # @option options [String] :proxy_server (nil) An HTTP proxy server FQDN
71
+ # @option options [String] :user_agent ("github-aws-ses-ruby-gem") The HTTP User-Agent header value
72
+ # @return [Object] the object.
73
+ def initialize( options = {} )
74
+
75
+ options = { :access_key_id => "",
76
+ :secret_access_key => "",
77
+ :use_ssl => true,
78
+ :server => DEFAULT_HOST,
79
+ :path => "/",
80
+ :user_agent => USER_AGENT,
81
+ :proxy_server => nil
82
+ }.merge(options)
83
+
84
+ @server = options[:server]
85
+ @proxy_server = options[:proxy_server]
86
+ @use_ssl = options[:use_ssl]
87
+ @path = options[:path]
88
+ @user_agent = options[:user_agent]
89
+
90
+ raise ArgumentError, "No :access_key_id provided" if options[:access_key_id].nil? || options[:access_key_id].empty?
91
+ raise ArgumentError, "No :secret_access_key provided" if options[:secret_access_key].nil? || options[:secret_access_key].empty?
92
+ raise ArgumentError, "No :use_ssl value provided" if options[:use_ssl].nil?
93
+ raise ArgumentError, "Invalid :use_ssl value provided, only 'true' or 'false' allowed" unless options[:use_ssl] == true || options[:use_ssl] == false
94
+ raise ArgumentError, "No :server provided" if options[:server].nil? || options[:server].empty?
95
+
96
+ if options[:port]
97
+ # user-specified port
98
+ @port = options[:port]
99
+ elsif @use_ssl
100
+ # https
101
+ @port = 443
102
+ else
103
+ # http
104
+ @port = 80
105
+ end
106
+
107
+ @access_key_id = options[:access_key_id]
108
+ @secret_access_key = options[:secret_access_key]
109
+
110
+ # Use proxy server if defined
111
+ # Based on patch by Mathias Dalheimer. 20070217
112
+ proxy = @proxy_server ? URI.parse(@proxy_server) : OpenStruct.new
113
+ @http = Net::HTTP::Proxy( proxy.host,
114
+ proxy.port,
115
+ proxy.user,
116
+ proxy.password).new(options[:server], @port)
117
+
118
+ @http.use_ssl = @use_ssl
119
+
120
+ # Don't verify the SSL certificates. Avoids SSL Cert warning in log on every GET.
121
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
122
+
123
+ end
124
+
125
+ attr_accessor :settings
126
+
127
+ def connection
128
+ @http
129
+ end
130
+
131
+ # Make the connection to AWS passing in our request.
132
+ # allow us to have a one line call in each method which will do all of the work
133
+ # in making the actual request to AWS.
134
+ def request(action, params = {})
135
+ # Use a copy so that we don't modify the caller's Hash, remove any keys that have nil or empty values
136
+ params = params.reject { |key, value| value.nil? or value.empty?}
137
+
138
+ timestamp = Time.now.getutc
139
+
140
+ params.merge!( {"Action" => action,
141
+ "SignatureVersion" => "2",
142
+ "SignatureMethod" => 'HmacSHA256',
143
+ "AWSAccessKeyId" => @access_key_id,
144
+ "Version" => API_VERSION,
145
+ "Timestamp" => timestamp.iso8601 } )
146
+
147
+ query = params.sort.collect do |param|
148
+ CGI::escape(param[0]) + "=" + CGI::escape(param[1])
149
+ end.join("&")
150
+
151
+ req = {}
152
+
153
+ req['X-Amzn-Authorization'] = get_aws_auth_param(timestamp.httpdate, @secret_access_key)
154
+ req['Date'] = timestamp.httpdate
155
+ req['User-Agent'] = @user_agent
156
+
157
+ response = connection.post(@path, query, req)
158
+
159
+ response_class = AWS::SES.const_get( "#{action}Response" )
160
+ result = response_class.new(action, response)
161
+
162
+ if result.error?
163
+ raise ResponseError.new(result)
164
+ end
165
+
166
+ result
167
+ end
168
+
169
+ # Set the Authorization header using AWS signed header authentication
170
+ def get_aws_auth_param(timestamp, secret_access_key)
171
+ encoded_canonical = SES.encode(secret_access_key, timestamp, false)
172
+ SES.authorization_header(@access_key_id, 'HmacSHA256', encoded_canonical)
173
+ end
174
+ end # class Base
175
+ end # Module SES
176
+ end # Module AWS