trikle-mail 0.0.5 → 0.0.6

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.
Files changed (4) hide show
  1. checksums.yaml +5 -5
  2. data/bin/trikle-mail +18 -120
  3. data/lib/triklemailer.rb +98 -0
  4. metadata +45 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a2d157ac21d41c5b4950c97d6fbce4d15c951fc1
4
- data.tar.gz: dfe235800e9add4a2e42d87586c91f27af1b4343
2
+ SHA256:
3
+ metadata.gz: 1bc1f6ac3d5593c2b07c79554fd73ac007913e2b8e257d044611328eca81d1c5
4
+ data.tar.gz: 779eb9f435e07e043f91d5eff45d2092a16076049157dbbbfaa1ee785b99cf5b
5
5
  SHA512:
6
- metadata.gz: 01145d358fd1aca7133654e41773ac3be5547314fa46642ac725d6f059bdd30db4060cf324a16a3802700e40b0138032a2873c8c9b5cc2bcae8976bc00d6fa7b
7
- data.tar.gz: 7d2e1a1b879315855b9ae375e94ed980adbf65b4c686cb173a5d3787075d0ca787e676c2ecc071553ce7977240f4474a323f2082ed9c9043bc24802e4f0f625d
6
+ metadata.gz: 7b9635c1c57938ea53c143458d48587234855f6b3910b1877c3f99b9bbedef48403748289338c38c2344b27e1915eec6806a8a3dd269225be85661d62fcc8eaa
7
+ data.tar.gz: baee1a420a5bcc5cd1ca280b3caee0aae9a0af0f98ff7d8423f49a7f90ab3e0c32cb639773decd0c3021a28edbf66ebbb21ef5d2c196741608099be655c2568e
data/bin/trikle-mail CHANGED
@@ -3,18 +3,19 @@ require 'commander'
3
3
  require 'mandrill'
4
4
  require 'csv'
5
5
  require 'mail'
6
+ require 'triklemailer'
6
7
 
7
8
  class TrikleMail
8
9
  extend Commander::Methods
9
10
 
10
11
  program :name, 'Trikle Mail'
11
- program :version, '0.0.0'
12
- program :description, 'Send your bulk email in a trikle over the mandril api'
12
+ program :version, Triklemailer::VERSION
13
+ program :description, 'Send your bulk email from the cli in a trikle'
13
14
 
14
- default_command :run
15
+ default_command :smtp
15
16
 
16
17
  command :smtp do |c|
17
- c.syntax = 'trikle-mail smtp csv_of_emails.csv [options]'
18
+ c.syntax = 'trikle-mail csv_of_emails.csv [options]'
18
19
  c.description = 'Send a message to each email in the csv using the template'
19
20
  c.option '--host STRING', String, 'The host of the mail server e.g. <mail.gmail.com>'
20
21
  c.option '--port INTEGER', Integer, 'Port number of the mail server e.g. 587'
@@ -28,122 +29,19 @@ class TrikleMail
28
29
  c.option '--minutes INTEGER', Integer, 'The number of minutes over which to send the emails'
29
30
 
30
31
  c.action do |args, options|
31
- title_row, *data_rows = CSV.read(args[0])
32
-
33
- data_hashes = data_rows.map do |row|
34
- title_row.map.with_index do |title, index|
35
- [title.downcase.to_sym, row[index]]
36
- end.to_h
37
- end
38
-
39
- options.default({hours: 0, minutes: 0, html: false})
40
-
41
- time_range = ((options.hours * 60 * 60) + (options.minutes * 60)) /
42
- data_hashes.length.to_f
43
-
44
- data_hashes.each do |hash|
45
- template = File.read(hash.fetch(:template, options.template)).
46
- gsub(/%(?!{)/, '%%') % hash
47
- mail = Mail.new do
48
- from hash.fetch(:from, options.from)
49
- to hash.fetch(:to, hash.fetch(:email) { raise 'no email address found in to column!' })
50
- subject hash.fetch(:subject, options.subject)
51
-
52
- if options.html
53
- html_part do
54
- content_type 'text/html; charset=UTF-8'
55
- body template
56
- end
57
- else
58
- text_part do
59
- body template
60
- end
61
- end
62
- end
63
-
64
- mail.delivery_method :smtp, {
65
- address: hash.fetch(:host, options.host),
66
- port: hash.fetch(:port, options.port),
67
- user_name: hash.fetch(:username, options.username),
68
- password: hash.fetch(:password, options.password),
69
- authentication: :login,
70
- enable_starttls_auto: true
71
- }
72
-
73
- puts mail.deliver!
74
- random_wait_time = rand(0..time_range)
75
- puts "waiting #{random_wait_time} seconds"
76
- sleep(random_wait_time)
77
- end
78
- end
79
- end
80
-
81
- command :run do |c|
82
- c.syntax = 'trikle-mail csv_of_emails.csv [options]'
83
- c.description = 'Send a message to each email address in the csv'
84
- c.option '--apikey STRING', String, 'The Mandrill API key'
85
- c.option '--from_email STRING', String, 'The email address of the sender'
86
- c.option '--from_name STRING', String, 'The name of the sender'
87
- c.option '--subject STRING', String, 'The subject line of the message'
88
- c.option '--template STRING', String, 'The template slug of the message template'
89
- c.option '--subaccount STRING', String, 'The mandril subaccount for this batch of email'
90
- c.option '--hours INTEGER', Integer, 'The number of hours over which to send the emails'
91
- c.option '--minutes INTEGER', Integer, 'The number of minutes over which to send the emails'
92
-
93
- c.action do |args, options|
94
- api = Mandrill::API.new(options.apikey)
95
-
96
- title_row, *data_rows = CSV.read(args[0])
97
-
98
- data_hashes = data_rows.map do |row|
99
- title_row.map.with_index do |title, index|
100
- [title.downcase, row[index]]
101
- end.to_h
102
- end
103
-
104
- options.default({hours: 0, minutes: 0})
105
- time_range = ((options.hours * 60 * 60) + (options.minutes * 60)) /
106
- data_hashes.length.to_f
107
-
108
- data_hashes.each do |hash|
109
- response = api.messages.send_template(
110
- hash['template'] || options.template,
111
- [],
112
- {
113
- subaccount: hash['subaccount'] || options.subaccount,
114
- subject: hash['subject'] || options.subject,
115
- from_email: hash['from_email'] || options.from_email,
116
- from_name: hash['from_name'] || options.from_name,
117
- to: [{
118
- email: hash['email'],
119
- name: hash['name'],
120
- type: 'to'
121
- }],
122
- merge_vars: [{
123
- rcpt: hash['email'],
124
- vars: hash.map { |key, value| { name: key, content: value } }
125
- }]
126
- }
127
- )
128
- TrikleMail.log(response)
129
- random_wait_time = rand(0..time_range)
130
- puts "waiting #{random_wait_time} seconds"
131
- sleep(random_wait_time)
132
- end
133
- end
134
- end
135
-
136
- def self.log(json)
137
- Array(json).each do |entry|
138
- # write to log file
139
- File.open('./log.json', 'a') { |f| f.write(JSON.dump(entry) + "\n") }
140
- # write nicely to cli
141
- puts [
142
- entry['status'],
143
- 'email to',
144
- entry['email'],
145
- entry['reject_reason'] ? "becuase #{entry['reject_reason']}" : ''
146
- ].join(' ')
32
+ recipients = CSV.new(args[0], headers: true).map(&:to_h)
33
+ sent_file_name = ['sent', options.template.split('.').first].join('_')
34
+ sent = CSV.new(sent_file_name, headers: true).map { |r| r[:email] }
35
+
36
+ mail_options = Triklemailer::Options.new(
37
+ template: File.read(options.template),
38
+ template_name: options.template,
39
+ is_html: options.template.end_with?('html'),
40
+ from: options.from,
41
+ subject: options.subject
42
+ )
43
+
44
+ Triklemailer.send_mail(mail_options, recipients, sent)
147
45
  end
148
46
  end
149
47
  end
@@ -0,0 +1,98 @@
1
+ require 'mail'
2
+ require 'csv'
3
+
4
+ module Triklemailer
5
+ VERSION = '0.0.6'
6
+ Options = Struct.new(:template, :template_name, :is_html, :from, :subject, keyword_init: true)
7
+
8
+ # It should take:
9
+ # * A list of emails and data
10
+ # * SMTP account details
11
+ # * A template
12
+ # * SMTP Server details
13
+ #
14
+ # and it should send an email to each email address from the csv using
15
+ # the template provided, filled in with the meta data provided for the
16
+ # email address. When each email is sent it should record that in a
17
+ # separate csv called sent_<template-name>.csv. Failures to send a
18
+ # messages should not be recorded. When sending emails it should check
19
+ # the sent_<template-name>.csv and if it exists, only send emails to
20
+ # email address not included in the sent_<template-name>.csv file.
21
+ #
22
+ # Read provided csv
23
+ # Check for sent_ csv
24
+ # For each email, meta_data in provided csv
25
+ # If email in sent_ csv
26
+ # Next email
27
+ #
28
+ # Read template file
29
+ # Apply meta_data to template file
30
+ # Send email with data from cli or meta data with template
31
+ # If there was an error sending
32
+ # Next email
33
+ # Record email sent to template in sent_ csv
34
+ #
35
+ def self.send_mail(options, recipients, sent)
36
+ cleaned_template = options.template.gsub(/%(?!{)/, '%%')
37
+
38
+ recipients.
39
+ reject { |recipient| sent.include?(recipient[:email]) }.
40
+ each do |recipient|
41
+ mail = Mail.new do
42
+ from recipient.fetch(:from, options.from)
43
+ to recipient.fetch(:to, recipient.fetch(:email) {
44
+ raise "Some rows are missing either a 'to' or 'email' column."
45
+ })
46
+ subject recipient.fetch(:subject, options.subject)
47
+
48
+ if options.is_html
49
+ html_part do
50
+ content_type 'text/html; charset=UTF-8'
51
+ body cleaned_template % recipient
52
+ end
53
+ else
54
+ text_part do
55
+ body cleaned_template % recipient
56
+ end
57
+ end
58
+ end
59
+
60
+ if block_given?
61
+ yield(mail, recipient)
62
+ else
63
+ mail.delivery_method :smtp, {
64
+ address: recipient.fetch(:host, options.host),
65
+ port: recipient.fetch(:port, options.port),
66
+ user_name: recipient.fetch(:username, options.username),
67
+ password: recipient.fetch(:password, options.password),
68
+ authentication: :login,
69
+ enable_starttls_auto: true
70
+ }
71
+ end
72
+
73
+ begin
74
+ mail.deliver!
75
+ # might fail in here though...
76
+ log_sent(
77
+ recipient.fetch(:to, recipient[:email]),
78
+ options.template_name)
79
+ rescue => e
80
+ puts "Failed to send email to #{recipient[:email]}."
81
+ next
82
+ end
83
+ end
84
+ end
85
+
86
+ def log_sent(email, template)
87
+ log_file_name = ['sent', template.split('.').first].join('_')
88
+
89
+ CSV.open(
90
+ "./#{log_file_name}.csv",
91
+ 'a',
92
+ write_headers: true,
93
+ headers: ['email', 'sent_at']
94
+ ) do |csv|
95
+ csv << [email, Time.now]
96
+ end
97
+ end
98
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trikle-mail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jasper Lyons
@@ -38,6 +38,48 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mail
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mail
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2'
41
83
  description: Send bulk email in a trickle over mandrill
42
84
  email: jasper.lyons@gmail.com
43
85
  executables:
@@ -46,6 +88,7 @@ extensions: []
46
88
  extra_rdoc_files: []
47
89
  files:
48
90
  - bin/trikle-mail
91
+ - lib/triklemailer.rb
49
92
  homepage: ''
50
93
  licenses:
51
94
  - MIT
@@ -65,10 +108,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
108
  - !ruby/object:Gem::Version
66
109
  version: '0'
67
110
  requirements: []
68
- rubyforge_project:
69
- rubygems_version: 2.5.1
111
+ rubygems_version: 3.0.3
70
112
  signing_key:
71
113
  specification_version: 4
72
114
  summary: Send a trickle of mail
73
115
  test_files: []
74
- has_rdoc: