vf-email-handler 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +37 -0
- data/bin/vf-email-handler +61 -0
- data/lib/initializers/aws.rb +14 -0
- data/lib/initializers/logger.rb +11 -0
- data/lib/interfaces/ses.rb +63 -0
- data/lib/interfaces/sqs.rb +42 -0
- data/lib/logger/logger.rb +32 -0
- data/lib/mailhandler.rb +56 -0
- data/lib/meta/console_strings.rb +58 -0
- data/lib/meta/sample-config.yml +14 -0
- data/lib/meta/version.rb +4 -0
- data/lib/models/email.rb +44 -0
- data/lib/workers/threaded_worker.rb +31 -0
- data/spec/integration_spec.rb +0 -0
- data/spec/interfaces/ses_spec.rb +42 -0
- data/spec/interfaces/sqs_spec.rb +90 -0
- data/spec/mail_handler_spec.rb +44 -0
- data/spec/spec_helper.rb +20 -0
- data/vf-email-handler.gemspec +43 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5d3dfd6e8bd814eb464375f2310eabcb1d2dbeb7
|
4
|
+
data.tar.gz: 35d8181ce32c6fe61c5a1959df0ee244512992a7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 31d8c82a3921232dd1479af035159aa6a0e21a9ce921bcadc9ce5744dbac24193463b6fc7ff668dd67320ca64a0fda1ac7fcce10b28082d4f807b32ef97a513f
|
7
|
+
data.tar.gz: ac941615464f4665fced5f48a7c8e9befb7bf6d2c1647e001ba47c6b21fa2d8e5a02d41655f7f5f16fa64b584bdfad2a3b751c3405480976946fcfe029431e41
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Videofy
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Videofy Email Handler
|
2
|
+
========
|
3
|
+
|
4
|
+
Logic that binds the Amazon SQS (Simple Queue Service) to the Amazon SES (Simple Email Service)
|
5
|
+
|
6
|
+
The handler will poll a specified SQS Queue and translate the messages to somethign that SES can understand and then push them to SES; effectively sending the emails.
|
7
|
+
|
8
|
+
####Get up and running with the mail handler
|
9
|
+
To start with there are some dependencies that must be satisfied.
|
10
|
+
* Ruby ( >= 2.1.2) must be installed on the host computer
|
11
|
+
* Rubygems (>= 1.8) to install the gem
|
12
|
+
|
13
|
+
To install just type `gem install vf-email-handler` and you're set to go.
|
14
|
+
|
15
|
+
Then there is just the matter of writing the config, which of course the handler can do for you; at least get you started.
|
16
|
+
Type the following:
|
17
|
+
|
18
|
+
```bash
|
19
|
+
Config create call here
|
20
|
+
```
|
21
|
+
|
22
|
+
and it will generate a config-skeleton for you. Looking inside `default.h.cfg` we se this:
|
23
|
+
|
24
|
+
```bash
|
25
|
+
Put sample config here
|
26
|
+
```
|
27
|
+
|
28
|
+
Fill in the blanks and then start the handler by running.
|
29
|
+
|
30
|
+
```bash
|
31
|
+
Put startup command here
|
32
|
+
```
|
33
|
+
|
34
|
+
#####Daemonize
|
35
|
+
There is an init.d script in the opt folder of the repo.
|
36
|
+
|
37
|
+
Happy hacking!
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'mailhandler'
|
3
|
+
require 'meta/console_strings'
|
4
|
+
require 'meta/version'
|
5
|
+
require 'initializers/aws'
|
6
|
+
require 'initializers/logger'
|
7
|
+
require 'aws/ses'
|
8
|
+
require 'aws/sqs'
|
9
|
+
|
10
|
+
include ConsoleStrings
|
11
|
+
|
12
|
+
def handle_path(path)
|
13
|
+
path[0] == '/' ? path : "#{Dir.pwd}/#{path}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def start(settings)
|
17
|
+
MailHandler::AWS.setup settings
|
18
|
+
MailHandler::Logger.setup settings
|
19
|
+
MailHandler::Handler.begin_work_loop
|
20
|
+
end
|
21
|
+
|
22
|
+
def copy_config
|
23
|
+
FileUtils.copy(
|
24
|
+
File.expand_path('../../lib/meta/sample-config.yml', __FILE__),
|
25
|
+
"#{Dir.pwd}/mailer_config.yml"
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
if ARGV.empty?
|
30
|
+
puts WELCOME
|
31
|
+
elsif ARGV.include?('--version') || ARGV.include?('-v')
|
32
|
+
puts VERSION
|
33
|
+
elsif ARGV.include?('--help') || ARGV.include?('-h')
|
34
|
+
puts HELP
|
35
|
+
elsif ARGV[0] == 'create-config'
|
36
|
+
copy_config
|
37
|
+
puts CONFIG_COPY_COMPLETE
|
38
|
+
elsif ARGV[0] == 'run'
|
39
|
+
puts STARTING
|
40
|
+
if ARGV[1]
|
41
|
+
begin
|
42
|
+
start YAML.load_file(handle_path(ARGV[1]))
|
43
|
+
puts STARTED
|
44
|
+
rescue Errno::ENOENT
|
45
|
+
puts MISSING_CONFIG
|
46
|
+
rescue AWS::SES::ResponseError, AWS::SQS::Errors::IncompleteSignature
|
47
|
+
puts BAD_AWS_CREDENTIALS
|
48
|
+
rescue AWS::SQS::Errors::NonExistentQueue
|
49
|
+
puts NO_SUCH_QUEUE
|
50
|
+
rescue StandardError
|
51
|
+
puts BAD_CONFIG
|
52
|
+
rescue SystemExit, Interrupt
|
53
|
+
puts 'Exiting.. '
|
54
|
+
exit 1
|
55
|
+
end
|
56
|
+
else
|
57
|
+
puts MISSING_CONFIG
|
58
|
+
end
|
59
|
+
else
|
60
|
+
puts UNRECOGNIZED % ARGV.join(' ')
|
61
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module MailHandler
|
2
|
+
# Initializes SES and SQS interfaces
|
3
|
+
module AWS
|
4
|
+
class << self
|
5
|
+
def setup(config)
|
6
|
+
require 'interfaces/sqs'
|
7
|
+
require 'interfaces/ses'
|
8
|
+
|
9
|
+
SES.setup config[:aws][:ses]
|
10
|
+
SQS.setup config[:aws][:sqs]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'aws/ses'
|
2
|
+
|
3
|
+
module MailHandler
|
4
|
+
# Containing everything related to SES comunication
|
5
|
+
module SES
|
6
|
+
# Setup and cofig the SES
|
7
|
+
class << self
|
8
|
+
attr_reader :mailer
|
9
|
+
|
10
|
+
def setup(config)
|
11
|
+
@mailer = Mailer.new config
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Yields an interface to SES
|
16
|
+
class Mailer
|
17
|
+
def initialize(config)
|
18
|
+
@ses = ::AWS::SES::Base.new(
|
19
|
+
access_key_id: config[:access_key_id],
|
20
|
+
secret_access_key: config[:secret_access_key],
|
21
|
+
server: config[:ses_server]
|
22
|
+
)
|
23
|
+
check_connection
|
24
|
+
end
|
25
|
+
|
26
|
+
def send_mail(email)
|
27
|
+
response = @ses.send_email email.to_h
|
28
|
+
log email, response
|
29
|
+
response
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def log(email, response)
|
35
|
+
if response.error?
|
36
|
+
log_failure email, response
|
37
|
+
else
|
38
|
+
log_success email
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def log_failure(email, response)
|
43
|
+
Logger.error(
|
44
|
+
subject: email,
|
45
|
+
error_code: response.code,
|
46
|
+
error_type: 'SES ERROR',
|
47
|
+
trace: response.error.to_s
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def log_success(email)
|
52
|
+
Logger.success(
|
53
|
+
subject: email,
|
54
|
+
message: 'successfully sent'
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_connection
|
59
|
+
@ses.quota
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
|
3
|
+
module MailHandler
|
4
|
+
# Contains everything rellated to SQS communication
|
5
|
+
module SQS
|
6
|
+
# Setup and cofig the sqs queue
|
7
|
+
class << self
|
8
|
+
attr_reader :client
|
9
|
+
|
10
|
+
def setup(config)
|
11
|
+
@client = Client.new config
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Yields an interface to a specific sqs queue
|
16
|
+
class Client
|
17
|
+
attr_accessor :queues
|
18
|
+
|
19
|
+
def initialize(config)
|
20
|
+
all_queues = ::AWS::SQS.new(
|
21
|
+
access_key_id: config[:access_key_id],
|
22
|
+
secret_access_key: config[:secret_access_key],
|
23
|
+
region: config[:aws_region]
|
24
|
+
).queues
|
25
|
+
|
26
|
+
@queues = config[:sqs_queues].map do |queue_name|
|
27
|
+
all_queues.named queue_name
|
28
|
+
end
|
29
|
+
|
30
|
+
@batch_size = config[:batch_size] || 1
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch_messages
|
34
|
+
[
|
35
|
+
@queues.map do |queue|
|
36
|
+
queue.receive_messages(limit: @batch_size)
|
37
|
+
end
|
38
|
+
].flatten.compact
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module MailHandler
|
2
|
+
# Custom logger that handles loging through STOUT
|
3
|
+
# or to a specified logfile
|
4
|
+
module Logger
|
5
|
+
# Setup and config the Logger
|
6
|
+
class << self
|
7
|
+
def setup(config)
|
8
|
+
if config
|
9
|
+
@logfile = File.open(config[:log_file], 'a') if config[:log_file]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def success(args)
|
14
|
+
#log "SUCCESS: #{args[:subject]}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def error(args)
|
18
|
+
str = "\n"
|
19
|
+
str << "ERROR: #{args[:error_type]}\n--\n" if args[:error_type]
|
20
|
+
str << "Error code: #{args[:error_code]}\n--\n" if args[:error_code]
|
21
|
+
str << "Subject: #{args[:subject]}\n--\n" if args[:subject]
|
22
|
+
str << "Trace: #{args[:trace]}\n--\n" if args[:trace]
|
23
|
+
str << "==\n"
|
24
|
+
log str
|
25
|
+
end
|
26
|
+
|
27
|
+
def log(string)
|
28
|
+
@logfile ? @logfile.puts(string) : puts(string)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/mailhandler.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'workers/threaded_worker'
|
2
|
+
require 'models/email'
|
3
|
+
|
4
|
+
module MailHandler
|
5
|
+
# Base handler that does it all
|
6
|
+
class Handler
|
7
|
+
def self.begin_work_loop
|
8
|
+
loop do
|
9
|
+
begin
|
10
|
+
new.do_work
|
11
|
+
rescue StandardError => e
|
12
|
+
Logger.error(
|
13
|
+
subject: 'Main loop',
|
14
|
+
error_type: e.class.to_s,
|
15
|
+
trace: e.to_s
|
16
|
+
)
|
17
|
+
raise e
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def do_work
|
23
|
+
if messages.any?
|
24
|
+
worker = ThreadedWorker.new(messages)
|
25
|
+
worker.do_work do |message|
|
26
|
+
unless send(email_from(message)).error?
|
27
|
+
message.delete
|
28
|
+
end
|
29
|
+
end
|
30
|
+
wait_for worker
|
31
|
+
else
|
32
|
+
sleep 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def messages
|
39
|
+
@messages ||= SQS.client.fetch_messages
|
40
|
+
end
|
41
|
+
|
42
|
+
def email_from(message)
|
43
|
+
MailHandler::Models::Email.new(
|
44
|
+
JSON.parse(message.body, symbolize_names: true)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def send(email)
|
49
|
+
SES.mailer.send_mail email
|
50
|
+
end
|
51
|
+
|
52
|
+
def wait_for(worker)
|
53
|
+
sleep(0.01) until worker.done?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'meta/version'
|
2
|
+
|
3
|
+
# Strings used by the console executable
|
4
|
+
# gathered in one place for less clutter
|
5
|
+
module ConsoleStrings
|
6
|
+
HELP = 'Usage: mail-handler [-v] [-h] [<args>]
|
7
|
+
|
8
|
+
-v, --version Print the version and exit.
|
9
|
+
-h, --help Print this help.
|
10
|
+
|
11
|
+
If no flags are specified <args> should be one of the following:
|
12
|
+
|
13
|
+
create-config Generates a config boilerplate
|
14
|
+
in current folder.
|
15
|
+
|
16
|
+
run [config-file] Run the handler, suplement path
|
17
|
+
to the config file.
|
18
|
+
|
19
|
+
'
|
20
|
+
WELCOME = 'Welcome to the Videofy email handeler!
|
21
|
+
|
22
|
+
One instance of the mail-handler will poll AWS SQS for messages
|
23
|
+
and then forward them to AWS SES.
|
24
|
+
|
25
|
+
Append -h flag for usage information.
|
26
|
+
|
27
|
+
'
|
28
|
+
VERSION = "Version : #{MailHandler::VERSION}"
|
29
|
+
|
30
|
+
UNRECOGNIZED = 'Did not understand argument: "%s"
|
31
|
+
Run me with -h to see what you can do.
|
32
|
+
'
|
33
|
+
|
34
|
+
STARTING = '
|
35
|
+
Handler is starting...
|
36
|
+
'
|
37
|
+
|
38
|
+
STARTED = 'Started
|
39
|
+
'
|
40
|
+
|
41
|
+
BAD_CONFIG = 'Something went wrong when parsing the config provided.
|
42
|
+
Make sure the config is valid YAML.
|
43
|
+
|
44
|
+
Run with --help for more information
|
45
|
+
'
|
46
|
+
|
47
|
+
NO_SUCH_QUEUE= ' One or more queues in your config could not be found.
|
48
|
+
'
|
49
|
+
|
50
|
+
MISSING_CONFIG = HELP
|
51
|
+
|
52
|
+
CONFIG_COPY_COMPLETE = '
|
53
|
+
mailer_config.yml generated in current folder.
|
54
|
+
'
|
55
|
+
BAD_AWS_CREDENTIALS = '
|
56
|
+
Could not connect to AWS, please ensure that your credentials are valid.
|
57
|
+
'
|
58
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
:aws:
|
2
|
+
:ses:
|
3
|
+
:access_key_id: <YOUR AWS ACCESS_KEY_ID>
|
4
|
+
:secret_access_key: <YOUR AWS SECRET_ACCESS_KEY>
|
5
|
+
:ses_server: email.eu-west-1.amazonaws.com
|
6
|
+
:sqs:
|
7
|
+
:access_key_id: <YOUR AWS ACCESS_KEY_ID>
|
8
|
+
:secret_access_key: <YOUR AWS SECRET_ACCESS_KEY>
|
9
|
+
:sqs_queues: [<NAMES OF YOUR AWS SQS QUEUES>]
|
10
|
+
:aws_region: eu-west-1
|
11
|
+
:batch_size: <OPTIONAL DEFAULT 1 MAX 10>
|
12
|
+
|
13
|
+
:logger:
|
14
|
+
:log_file: <PATH TO LOGFILE HERE; Null if STOUT>
|
data/lib/meta/version.rb
ADDED
data/lib/models/email.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module MailHandler
|
2
|
+
module Models
|
3
|
+
# PORO for mutating email information
|
4
|
+
class Email
|
5
|
+
attr_reader :from, :to, :cc, :bcc, :subject, :html,
|
6
|
+
:text, :reply_to, :bounce_to
|
7
|
+
|
8
|
+
def initialize(email_hash = {})
|
9
|
+
@from = email_hash[:from]
|
10
|
+
|
11
|
+
@to = email_hash[:to]
|
12
|
+
@cc = email_hash[:cc]
|
13
|
+
@bcc = email_hash[:bcc]
|
14
|
+
|
15
|
+
@subject = email_hash[:subject]
|
16
|
+
@text = email_hash[:text]
|
17
|
+
@html = email_hash[:html]
|
18
|
+
|
19
|
+
@reply_to = email_hash[:reply_to]
|
20
|
+
@bounce_to = email_hash[:bounce_to]
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_h
|
24
|
+
{ from: from,
|
25
|
+
to: to,
|
26
|
+
cc: cc,
|
27
|
+
bcc: bcc,
|
28
|
+
subject: subject,
|
29
|
+
html_body: html,
|
30
|
+
text_body: text,
|
31
|
+
return_path: bounce_to,
|
32
|
+
reply: reply_to }.delete_if { |_, v| v.nil? }
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
{
|
37
|
+
from: from,
|
38
|
+
to: to,
|
39
|
+
subject: subject
|
40
|
+
}.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module MailHandler
|
2
|
+
# Generic threaded worker
|
3
|
+
class ThreadedWorker
|
4
|
+
WORKER_SIZE = 10
|
5
|
+
|
6
|
+
def initialize(task_list)
|
7
|
+
@tasks = Queue.new
|
8
|
+
populate_que task_list
|
9
|
+
end
|
10
|
+
|
11
|
+
def do_work
|
12
|
+
WORKER_SIZE.times do
|
13
|
+
Thread.new do
|
14
|
+
while (task = @tasks.pop)
|
15
|
+
yield task
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def done?
|
22
|
+
@tasks.size.zero?
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def populate_que(task_list)
|
28
|
+
task_list.each { |task| @tasks << task }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
File without changes
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'interfaces/ses'
|
3
|
+
require 'models/email'
|
4
|
+
require 'logger/logger'
|
5
|
+
|
6
|
+
describe 'SES' do
|
7
|
+
|
8
|
+
let(:email) { MailHandler::Models::Email.new({}) }
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
@ses = double
|
12
|
+
|
13
|
+
allow(AWS::SES::Base).to receive(:new).and_return(@ses)
|
14
|
+
allow(@ses).to receive(:quota).and_return(true)
|
15
|
+
|
16
|
+
MailHandler::SES.setup({})
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#send_mail' do
|
20
|
+
subject { MailHandler::SES.mailer }
|
21
|
+
|
22
|
+
let(:success) { double(error?: false) }
|
23
|
+
|
24
|
+
let(:failure) { double(error?: true, error: 'Error String', code: 400) }
|
25
|
+
|
26
|
+
it 'handles successfully sent mail' do
|
27
|
+
allow(@ses).to receive(:send_email)
|
28
|
+
.with(email.to_h).and_return(success)
|
29
|
+
|
30
|
+
expect(MailHandler::Logger).to receive(:success).once
|
31
|
+
expect(subject.send_mail(email).error?).to eq false
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'handles failures while sending mail' do
|
35
|
+
allow(@ses).to receive(:send_email)
|
36
|
+
.with(email.to_h).and_return(failure)
|
37
|
+
|
38
|
+
expect(MailHandler::Logger).to receive(:error).once
|
39
|
+
expect(subject.send_mail(email).error?).to eq true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'interfaces/sqs'
|
3
|
+
|
4
|
+
describe 'SQS', :sqs do
|
5
|
+
|
6
|
+
SQS_CONFIG = {
|
7
|
+
access_key_id: 'fake access key',
|
8
|
+
secret_access_key: 'fake secret key',
|
9
|
+
sqs_queues: %w(q1 q2),
|
10
|
+
batch_size: 3
|
11
|
+
}
|
12
|
+
|
13
|
+
before :all do
|
14
|
+
@sqs = AWS::SQS.new(SQS_CONFIG)
|
15
|
+
|
16
|
+
@q1 = @sqs.queues.create('q1')
|
17
|
+
@q2 = @sqs.queues.create('q2')
|
18
|
+
|
19
|
+
MailHandler::SQS.setup(SQS_CONFIG)
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:email) do
|
23
|
+
{
|
24
|
+
from: 'email@email.com',
|
25
|
+
to: 'email2@email.com',
|
26
|
+
subject: 'testing',
|
27
|
+
text: 'testing text',
|
28
|
+
reply_to: 'noreply@email.com'
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#fetch_messages' do
|
33
|
+
subject do
|
34
|
+
MailHandler::SQS.client.fetch_messages.map do |msg|
|
35
|
+
JSON.parse(msg.body, symbolize_names: true)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when no messages' do
|
40
|
+
it { is_expected.to be_empty }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when one message' do
|
44
|
+
describe 'from one queue' do
|
45
|
+
before { @q1.send_message(JSON.dump(email)) }
|
46
|
+
|
47
|
+
it { is_expected.to eq [email] }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'from multiple queues' do
|
51
|
+
before { [@q1, @q2].each { |q| q.send_message(JSON.dump email) } }
|
52
|
+
|
53
|
+
it { is_expected.to eq [email, email] }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when multiple messages' do
|
58
|
+
describe 'from one queue' do
|
59
|
+
before { 4.times { @q1.send_message(JSON.dump email) } }
|
60
|
+
|
61
|
+
it { is_expected.to eq 3.times.map { email } }
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'from multiple queues' do
|
65
|
+
before do
|
66
|
+
[@q1, @q2].each { |q| 4.times { q.send_message(JSON.dump email) } }
|
67
|
+
end
|
68
|
+
|
69
|
+
it { is_expected.to eq 6.times.map { email } }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'deleting messages' do
|
75
|
+
subject { MailHandler::SQS.client.fetch_messages }
|
76
|
+
|
77
|
+
before { @q1.send_message(JSON.dump email) }
|
78
|
+
|
79
|
+
context 'when not yet deleted' do
|
80
|
+
it { is_expected.not_to be_empty }
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when deleted' do
|
84
|
+
before { MailHandler::SQS.client.fetch_messages.first.delete }
|
85
|
+
|
86
|
+
it { is_expected.to be_empty }
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mailhandler'
|
3
|
+
|
4
|
+
describe 'MailHandler' do
|
5
|
+
before { @handler = MailHandler::Handler.new }
|
6
|
+
|
7
|
+
describe '#do_work' do
|
8
|
+
context 'when no messages' do
|
9
|
+
before(:each) { allow(@handler).to receive(:messages) { [] } }
|
10
|
+
|
11
|
+
it 'should go straight for sleep' do
|
12
|
+
expect(@handler).to receive(:sleep).with(1) { true }
|
13
|
+
@handler.do_work
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when messages' do
|
18
|
+
let(:message) { double }
|
19
|
+
let(:email) { double }
|
20
|
+
|
21
|
+
before(:each) do
|
22
|
+
allow(@handler).to receive(:messages) { [message] }
|
23
|
+
allow(@handler).to receive(:email_from).with(message) { email }
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should try to send the messages' do
|
27
|
+
expect(@handler).to receive(:send).with(email)
|
28
|
+
@handler.do_work
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should delete the messages unless errors' do
|
32
|
+
expect(@handler).to receive(:send) { double(:error? => false) }
|
33
|
+
expect(message).to receive(:delete)
|
34
|
+
@handler.do_work
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should not delete the messages if errors' do
|
38
|
+
expect(@handler).to receive(:send) { double(:error? => true) }
|
39
|
+
expect(message).not_to receive(:delete)
|
40
|
+
@handler.do_work
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'fake_sqs/test_integration'
|
3
|
+
|
4
|
+
AWS.config(
|
5
|
+
use_ssl: false,
|
6
|
+
sqs_endpoint: 'localhost',
|
7
|
+
sqs_port: 4568,
|
8
|
+
access_key_id: 'fake access key',
|
9
|
+
secret_access_key: 'fake secret key'
|
10
|
+
)
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.before(:suite) do
|
14
|
+
FAKE_SQS = FakeSQS::TestIntegration.new(database: ':memory:')
|
15
|
+
end
|
16
|
+
|
17
|
+
config.before(:all, :sqs) { FAKE_SQS.start }
|
18
|
+
|
19
|
+
config.after(:all, :sqs) { FAKE_SQS.stop }
|
20
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'meta/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = 'vf-email-handler'
|
9
|
+
s.version = MailHandler::VERSION
|
10
|
+
s.date = Date.today.to_s
|
11
|
+
s.authors = ['Videofy', 'Karl Litterfeldt']
|
12
|
+
s.email = 'karl.litterfeldt@videofy.me'
|
13
|
+
s.license = 'MIT-LICENSE'
|
14
|
+
|
15
|
+
s.required_ruby_version = '>=2.1.2'
|
16
|
+
|
17
|
+
s.homepage = 'http://www.videofy.me'
|
18
|
+
|
19
|
+
s.summary = 'Integrates AWS SQS with SES letting you' \
|
20
|
+
'seemlessly queue emails for sending'
|
21
|
+
|
22
|
+
s.description = 'Use this handler when you want to be able' \
|
23
|
+
'to queue up emails via Amazons Simple Queue' \
|
24
|
+
'Service, enabeling you to generate' \
|
25
|
+
'tons of emails and send them as fast as Amazons' \
|
26
|
+
'Simple Email Service will let you. Check out the' \
|
27
|
+
'readme on Github for more information.'
|
28
|
+
|
29
|
+
s.files = Dir.glob('lib/**/*') +
|
30
|
+
Dir.glob('bin/**/*') +
|
31
|
+
%w(vf-email-handler.gemspec LICENSE README.md)
|
32
|
+
|
33
|
+
s.test_files = Dir.glob('spec/**/*')
|
34
|
+
s.executables = %w(vf-email-handler)
|
35
|
+
s.require_paths = ['lib']
|
36
|
+
|
37
|
+
s.add_dependency 'aws-ses', '~> 0.5'
|
38
|
+
s.add_dependency 'aws-sdk', '~> 1.49.0'
|
39
|
+
|
40
|
+
s.add_development_dependency 'rspec', '~> 3'
|
41
|
+
s.add_development_dependency 'cane', '~> 2.6'
|
42
|
+
s.add_development_dependency 'fake_sqs', '~> 0.1'
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vf-email-handler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Videofy
|
8
|
+
- Karl Litterfeldt
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-08-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: aws-ses
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0.5'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0.5'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: aws-sdk
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.49.0
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 1.49.0
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '3'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: cane
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '2.6'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2.6'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: fake_sqs
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0.1'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0.1'
|
84
|
+
description: Use this handler when you want to be ableto queue up emails via Amazons
|
85
|
+
Simple QueueService, enabeling you to generatetons of emails and send them as fast
|
86
|
+
as AmazonsSimple Email Service will let you. Check out thereadme on Github for more
|
87
|
+
information.
|
88
|
+
email: karl.litterfeldt@videofy.me
|
89
|
+
executables:
|
90
|
+
- vf-email-handler
|
91
|
+
extensions: []
|
92
|
+
extra_rdoc_files: []
|
93
|
+
files:
|
94
|
+
- LICENSE
|
95
|
+
- README.md
|
96
|
+
- bin/vf-email-handler
|
97
|
+
- lib/initializers/aws.rb
|
98
|
+
- lib/initializers/logger.rb
|
99
|
+
- lib/interfaces/ses.rb
|
100
|
+
- lib/interfaces/sqs.rb
|
101
|
+
- lib/logger/logger.rb
|
102
|
+
- lib/mailhandler.rb
|
103
|
+
- lib/meta/console_strings.rb
|
104
|
+
- lib/meta/sample-config.yml
|
105
|
+
- lib/meta/version.rb
|
106
|
+
- lib/models/email.rb
|
107
|
+
- lib/workers/threaded_worker.rb
|
108
|
+
- spec/integration_spec.rb
|
109
|
+
- spec/interfaces/ses_spec.rb
|
110
|
+
- spec/interfaces/sqs_spec.rb
|
111
|
+
- spec/mail_handler_spec.rb
|
112
|
+
- spec/spec_helper.rb
|
113
|
+
- vf-email-handler.gemspec
|
114
|
+
homepage: http://www.videofy.me
|
115
|
+
licenses:
|
116
|
+
- MIT-LICENSE
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 2.1.2
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 2.2.2
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Integrates AWS SQS with SES letting youseemlessly queue emails for sending
|
138
|
+
test_files:
|
139
|
+
- spec/integration_spec.rb
|
140
|
+
- spec/interfaces/ses_spec.rb
|
141
|
+
- spec/interfaces/sqs_spec.rb
|
142
|
+
- spec/mail_handler_spec.rb
|
143
|
+
- spec/spec_helper.rb
|