maildis 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +2 -0
- data/Guardfile +24 -0
- data/LICENSE.txt +22 -0
- data/README.md +134 -0
- data/Rakefile +11 -0
- data/bin/maildis +5 -0
- data/lib/maildis/dispatcher.rb +43 -0
- data/lib/maildis/merge_field.rb +9 -0
- data/lib/maildis/multi_io.rb +15 -0
- data/lib/maildis/recipient.rb +22 -0
- data/lib/maildis/recipient_parser.rb +87 -0
- data/lib/maildis/sender.rb +17 -0
- data/lib/maildis/server_utils.rb +20 -0
- data/lib/maildis/smtp_server.rb +13 -0
- data/lib/maildis/template.rb +17 -0
- data/lib/maildis/template_loader.rb +18 -0
- data/lib/maildis/template_renderer.rb +20 -0
- data/lib/maildis/validation_error.rb +3 -0
- data/lib/maildis/validation_utils.rb +19 -0
- data/lib/maildis/validator.rb +50 -0
- data/lib/maildis/version.rb +3 -0
- data/lib/maildis.rb +118 -0
- data/maildis.gemspec +33 -0
- data/spec/lib/maildis/dispatcher_spec.rb +31 -0
- data/spec/lib/maildis/maildis_spec.rb +84 -0
- data/spec/lib/maildis/merge_field_spec.rb +15 -0
- data/spec/lib/maildis/recipient_parser_spec.rb +39 -0
- data/spec/lib/maildis/recipient_spec.rb +16 -0
- data/spec/lib/maildis/sender_spec.rb +15 -0
- data/spec/lib/maildis/smtp_server_spec.rb +17 -0
- data/spec/lib/maildis/template_loader_spec.rb +25 -0
- data/spec/lib/maildis/template_renderer_spec.rb +26 -0
- data/spec/lib/maildis/template_spec.rb +15 -0
- data/spec/lib/maildis/validator_spec.rb +132 -0
- data/spec/mailer/empty.csv +0 -0
- data/spec/mailer/invalid.csv +1 -0
- data/spec/mailer/mailer.yml +15 -0
- data/spec/mailer/mailer_invalid.yml +1 -0
- data/spec/mailer/recipients.csv +1 -0
- data/spec/mailer/recipients_empty.csv +1 -0
- data/spec/mailer/template.html +13 -0
- data/spec/mailer/template.txt +5 -0
- data/spec/spec_helper.rb +2 -0
- metadata +291 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec' do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
|
17
|
+
# Capybara features specs
|
18
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
19
|
+
|
20
|
+
# Turnip features and steps
|
21
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
22
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
23
|
+
end
|
24
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Johnny Boursiquot
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
# Maildis
|
2
|
+
|
3
|
+
[![Code
|
4
|
+
Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/jboursiquot/maildis) [![Dependency
|
5
|
+
Status](https://gemnasium.com/jboursiquot/maildis.png)](https://gemnasium.com/jboursiquot/maildis)
|
6
|
+
|
7
|
+
Maildis is a command line bulk email dispatching tool. It supports HTML and plain text templates and CSVs for recipients and merge fields. It relies on SMTP information you provide through your own configuration file. Subject, sender, path to CSV and path to the templates are all configurable through YAML.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
$ gem install maildis
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
### Maildis Commands:
|
16
|
+
|
17
|
+
maildis dispatch mailer # Dispatches the mailer through the SMTP server specified in the mailer configuration.
|
18
|
+
maildis ping mailer # Attempts to connect to the SMTP server specified in the mailer configuration
|
19
|
+
maildis validate mailer # Validates mailer configuration file
|
20
|
+
|
21
|
+
In the above task listing, _mailer_ refers to a YAML configuration file
|
22
|
+
for your mailer. You may get additional help on any of the available tasks, for example:
|
23
|
+
|
24
|
+
$ maildis help dispath
|
25
|
+
|
26
|
+
Usage:
|
27
|
+
maildis ping mailer
|
28
|
+
|
29
|
+
Options:
|
30
|
+
-v, [--verbose=VERBOSE] # Verbose
|
31
|
+
|
32
|
+
## Creating and Dispatching Mailers
|
33
|
+
|
34
|
+
### 1. Create a mailer configuration (e.g. mailer.yml)
|
35
|
+
|
36
|
+
mailer:
|
37
|
+
subject: "Test Mailer"
|
38
|
+
sender:
|
39
|
+
name: "Developer"
|
40
|
+
email: "developer@company.com"
|
41
|
+
recipients:
|
42
|
+
csv: "/path/to/recipients.csv"
|
43
|
+
templates:
|
44
|
+
html: "/path/to/template.html"
|
45
|
+
plain: "/path/to/template.txt"
|
46
|
+
smtp:
|
47
|
+
host: "my.mail.host"
|
48
|
+
port: 25
|
49
|
+
username: "username"
|
50
|
+
password: "password"
|
51
|
+
|
52
|
+
### 2. Set up html and plain text templates, for example:
|
53
|
+
|
54
|
+
**HTML**
|
55
|
+
|
56
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
57
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
58
|
+
<html>
|
59
|
+
<head>
|
60
|
+
<title>Test Mailer</title>
|
61
|
+
</head>
|
62
|
+
<body>
|
63
|
+
<p>This is a test mailer</p>
|
64
|
+
<p>The following merge field should be replaced with an actual URL: <a href="%url%">%url%</a></p>
|
65
|
+
<p>Organization | Address | Unsubscribe Link</p>
|
66
|
+
</body>
|
67
|
+
</html>
|
68
|
+
|
69
|
+
**Plain**
|
70
|
+
|
71
|
+
This is a test mailer.
|
72
|
+
|
73
|
+
The following merge field should be replaced with an actual URL: %url%
|
74
|
+
|
75
|
+
Organization | Address | Unsubscribe Link
|
76
|
+
|
77
|
+
Note the _%url%_ markers in the template files. This %{string}%
|
78
|
+
mechanism allows you to specify merge fields which are replaced by their
|
79
|
+
equivalent columns from your recipients CSV. In this case, the CSV example below,
|
80
|
+
lists a _url_ column that will be used as a merge field.
|
81
|
+
|
82
|
+
### 3. Prepare your recipients CSV, for example:
|
83
|
+
|
84
|
+
name,email,url
|
85
|
+
Johnny Boursiquot,jboursiquot@gmail.com,https://github.com/jboursiquot
|
86
|
+
Johnny Boursiquot,jboursiquot@maark.com,http://www.maark.com
|
87
|
+
|
88
|
+
### 4. Validate your configuration
|
89
|
+
|
90
|
+
$ maildis validate /path/to/your/mailer.yml
|
91
|
+
|
92
|
+
This will go through the settings in your mailer configuration and check
|
93
|
+
|
94
|
+
- sender email validity
|
95
|
+
- template path validity
|
96
|
+
- recipients CSV path and format validity
|
97
|
+
- SMTP server reachability
|
98
|
+
|
99
|
+
You can test the reachability of the SMTP server defined in your mailer configuration on its own by issueing the following command:
|
100
|
+
|
101
|
+
$ maildis ping /path/to/your/mailer.yml
|
102
|
+
|
103
|
+
### 5. Invoke the maildis command while passing in the path to your
|
104
|
+
mailer configuration to its dispatch task
|
105
|
+
|
106
|
+
$ maildis dispath /path/to/your/mailer.yml -v
|
107
|
+
|
108
|
+
When _maildis_ processes your _dispatch_ request, a logfile (.maildis.log) is written in the user's home directory. In the above command, the _dispatch_ task is invoked with the _verbose_ flag which will output to STDOUT as well as ~/.maildis.log. Example output based on the recipients.csv above might look like this:
|
109
|
+
|
110
|
+
2012-12-11 20:18:10 -0500 INFO: Load /path/to/your/mailer.yml
|
111
|
+
2012-12-11 20:18:10 -0500 INFO: Validate configuration
|
112
|
+
2012-12-11 20:18:10 -0500 INFO: Validate recipients csv
|
113
|
+
2012-12-11 20:18:10 -0500 INFO: Extract recipients from csv
|
114
|
+
2012-12-11 20:18:10 -0500 INFO: Validate sender
|
115
|
+
2012-12-11 20:18:10 -0500 INFO: Validate templates
|
116
|
+
2012-12-11 20:18:10 -0500 INFO: Validate SMTP server localhost
|
117
|
+
2012-12-11 20:18:10 -0500 INFO: Dispatching to 2 recipients
|
118
|
+
2012-12-11 20:18:10 -0500 INFO: Sent: Johnny Boursiquot <jboursiquot@gmail.com>
|
119
|
+
2012-12-11 20:18:10 -0500 INFO: Sent: Johnny Boursiquot <jboursiquot@maark.com>
|
120
|
+
2012-12-11 20:18:11 -0500 INFO: Dispatch complete without errors
|
121
|
+
|
122
|
+
## Local SMTP Server For Testing
|
123
|
+
|
124
|
+
I recommend you use the _mailcatcher_ gem to get a local SMTP server up
|
125
|
+
and running while you test. This will speed up your testing and even
|
126
|
+
require network access. See http://mailcatcher.me for more details.
|
127
|
+
|
128
|
+
## Contributing
|
129
|
+
|
130
|
+
1. Fork it
|
131
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
132
|
+
3. Commit your changes with tests (`git commit -am 'Add some feature'`)
|
133
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
134
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
task :default => [:spec]
|
6
|
+
|
7
|
+
desc 'Runs all specs'
|
8
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
9
|
+
spec.pattern = "spec/**/*_spec.rb"
|
10
|
+
spec.rspec_opts = ["--format Fivemat", "--color"]
|
11
|
+
end
|
data/bin/maildis
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require "pony"
|
2
|
+
require "logger"
|
3
|
+
|
4
|
+
module Maildis
|
5
|
+
|
6
|
+
class Dispatcher
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def dispatch(options = {})
|
11
|
+
result = {sent: [], not_sent: []}
|
12
|
+
options[:recipients].each do |recipient|
|
13
|
+
begin
|
14
|
+
html_body = TemplateRenderer.render(options[:templates][:html], recipient.merge_fields)
|
15
|
+
plain_body = TemplateRenderer.render(options[:templates][:plain], recipient.merge_fields)
|
16
|
+
Pony.mail({
|
17
|
+
to: recipient.to_email,
|
18
|
+
from: options[:sender].to_email,
|
19
|
+
subject: options[:subject],
|
20
|
+
html_body: html_body,
|
21
|
+
body: plain_body,
|
22
|
+
via: :smtp,
|
23
|
+
via_options: {address: options[:server].host,
|
24
|
+
port: options[:server].port,
|
25
|
+
user_name: options[:server].username,
|
26
|
+
password: options[:server].password}
|
27
|
+
})
|
28
|
+
options[:logger].info "Sent: #{recipient.to_email}" if options[:logger]
|
29
|
+
result[:sent] << recipient
|
30
|
+
rescue => e
|
31
|
+
options[:logger].error "Error: #{recipient.to_email} | #{e.message}" if options[:logger]
|
32
|
+
result[:not_sent] << {recipient: recipient, reason: e.message}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Maildis
|
2
|
+
class Recipient
|
3
|
+
attr_reader :name, :email
|
4
|
+
attr_accessor :merge_fields
|
5
|
+
|
6
|
+
def initialize(name, email, merge_fields=[])
|
7
|
+
@name = name
|
8
|
+
@email = email
|
9
|
+
@merge_fields = merge_fields
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_email
|
13
|
+
return "#{@name} <#{@email}>" if @name
|
14
|
+
@email
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"<Recipient #{name} | #{email}>"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require_relative 'validation_error'
|
2
|
+
require_relative 'recipient'
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
module Maildis
|
6
|
+
|
7
|
+
class RecipientParser
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
@@expected_columns = [:name, :email]
|
12
|
+
|
13
|
+
def valid_csv?(file_path)
|
14
|
+
csv = extract_data file_path
|
15
|
+
begin
|
16
|
+
validate_headers(normalize_headers(csv.headers), @@expected_columns)
|
17
|
+
true
|
18
|
+
rescue ValidationError => e
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def empty_csv?(file_path)
|
24
|
+
csv = extract_data file_path
|
25
|
+
csv.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def extract_recipients(file_path)
|
29
|
+
validate_file_path file_path
|
30
|
+
csv = extract_data file_path
|
31
|
+
validate_headers(normalize_headers(csv.headers), @@expected_columns)
|
32
|
+
parse_csv(csv)
|
33
|
+
end
|
34
|
+
|
35
|
+
def extract_data(file_path)
|
36
|
+
begin
|
37
|
+
CSV.read(file_path, {headers: true})
|
38
|
+
rescue ArgumentError => e
|
39
|
+
begin
|
40
|
+
# Force UTF-8
|
41
|
+
data = IO.read(file_path).force_encoding("ISO-8859-1").encode("utf-8", replace: nil)
|
42
|
+
CSV.parse(data, {headers: true})
|
43
|
+
rescue => e
|
44
|
+
raise "Failed to parse CSV. Unable to force UTF-8 conversion."+ " " + e.message
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_csv(csv)
|
50
|
+
result = []
|
51
|
+
csv.each do |r|
|
52
|
+
row = {}
|
53
|
+
r.to_hash.each_pair {|k,v| row.merge!({k.downcase => v})}
|
54
|
+
result << recipient_instance(row)
|
55
|
+
end
|
56
|
+
result
|
57
|
+
end
|
58
|
+
|
59
|
+
def recipient_instance(row)
|
60
|
+
recipient = Recipient.new row['name'], row['email']
|
61
|
+
row.each do |key, value|
|
62
|
+
recipient.merge_fields << MergeField.new(key, value) unless %w{name email}.include? key
|
63
|
+
end
|
64
|
+
recipient
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse_file(file_path)
|
68
|
+
IO.read(file_path).force_encoding("ISO-8859-1").encode("utf-8", replace: nil)
|
69
|
+
end
|
70
|
+
|
71
|
+
def normalize_headers(headers)
|
72
|
+
headers.map(&:downcase)
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate_file_path(file_path)
|
76
|
+
raise ValidationError, "File not found: #{file_path}" unless File.exists?(file_path)
|
77
|
+
end
|
78
|
+
|
79
|
+
def validate_headers(headers, expected)
|
80
|
+
expected.each do |header|
|
81
|
+
raise ValidationError, "Missing '#{header.to_s}' column" unless headers.include? header.to_s
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
class ServerUtils
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def server_reachable?(host, port=25)
|
8
|
+
begin
|
9
|
+
TCPSocket.new(host, port).close
|
10
|
+
true
|
11
|
+
rescue Errno::ECONNREFUSED
|
12
|
+
false
|
13
|
+
rescue => e
|
14
|
+
$stderr.puts "Error during mail server status check: " + e.message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Maildis
|
2
|
+
|
3
|
+
class TemplateLoader
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def load(template_path)
|
8
|
+
path = File.expand_path(template_path)
|
9
|
+
type = File.extname(path) == Template::PLAIN_EXT ? Template::PLAIN : Template::HTML
|
10
|
+
content = File.read path
|
11
|
+
Template.new type, content
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Maildis
|
2
|
+
|
3
|
+
class TemplateRenderer
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def render(template, merge_fields)
|
8
|
+
result = String.new(template.content)
|
9
|
+
merge_fields.each do |mf|
|
10
|
+
token = /#{Regexp.quote('%' + mf.field + '%')}/
|
11
|
+
result.gsub!(token, mf.value)
|
12
|
+
end
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class ValidationUtils
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def valid_hostname?(hostname)
|
6
|
+
return false unless hostname
|
7
|
+
return false if hostname.length > 255 || hostname.scan('..').any?
|
8
|
+
return true if hostname == 'localhost'
|
9
|
+
hostname = hostname[0 ... -1] if hostname.index('.', -1)
|
10
|
+
return hostname.split('.').collect { |i| i.size <= 63 && !(i.rindex('-', 0) || i.index('-', -1) || i.scan(/[^a-z\d-]/i).any?)}.all?
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid_email?(email)
|
14
|
+
!email.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i).nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'validation_utils'
|
2
|
+
require_relative 'validation_error'
|
3
|
+
require_relative 'recipient_parser'
|
4
|
+
|
5
|
+
module Maildis
|
6
|
+
|
7
|
+
class Validator
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def validate_config(hash)
|
12
|
+
raise ValidationError, "mailer settings missing" unless hash.has_key? 'mailer'
|
13
|
+
raise ValidationError, "smtp settings missing" unless hash.has_key? 'smtp'
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_subject(subject)
|
17
|
+
raise ValidationError, "mailer::subject invalid" unless !subject.nil? && !subject.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate_smtp(hash)
|
21
|
+
raise ValidationError, "smtp::host missing or invalid" unless hash.has_key?('host') && ValidationUtils.valid_hostname?(hash['host'])
|
22
|
+
raise ValidationError, "smtp::port missing or invalid" unless hash.has_key?('port') && (hash['port'].to_i != 0)
|
23
|
+
raise ValidationError, "smtp::username missing" unless hash.has_key? 'username'
|
24
|
+
raise ValidationError, "smtp::password missing" unless hash.has_key? 'password'
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate_sender(hash)
|
28
|
+
raise ValidationError, "sender::name missing" unless hash.has_key? 'name'
|
29
|
+
raise ValidationError, "sender::email missing or invalid" unless hash.has_key?('email') && ValidationUtils.valid_email?(hash['email'])
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate_recipients(hash)
|
33
|
+
raise ValidationError, "recipients::csv missing" unless hash.has_key? 'csv'
|
34
|
+
raise ValidationError, "recipients::csv invalid file path" unless File.exist?(File.expand_path(hash['csv']))
|
35
|
+
raise ValidationError, "recipients::csv empty" if RecipientParser.empty_csv? hash['csv']
|
36
|
+
raise ValidationError, "recipients::csv invalid column headers" unless RecipientParser.valid_csv? hash['csv']
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate_templates(hash)
|
40
|
+
raise ValidationError, "templates::html not specified" unless hash.has_key? 'html'
|
41
|
+
raise ValidationError, "templates::plain not specified" unless hash.has_key? 'plain'
|
42
|
+
raise ValidationError, "templates::html not found" unless File.exist?(File.expand_path(hash['html']))
|
43
|
+
raise ValidationError, "templates::plain not found" unless File.exist?(File.expand_path(hash['plain']))
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|