snails 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/snails/mailer.rb +127 -26
  3. data/snails.gemspec +1 -1
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9ee5f0ad2cdda5a366dfc31d197b29948e63b7d24be394e8a6b779ea0f11bc2
4
- data.tar.gz: 6f838a808f32036b57ab67ae24e26e2cae9442af0b086aa7d524d78d94ae5df2
3
+ metadata.gz: 06b4aea8ffe430adc00748ea5f48ace43cd79fdf26cebb02da08b31ea88765ac
4
+ data.tar.gz: 9c856ce125123fe7d3423b362ea948dba6b41038490dea3b0158084ecf2d6b35
5
5
  SHA512:
6
- metadata.gz: f4b100c320293b3f66944182bde37c32567795838358c09bad18cf94ec34ce91932d5e923245faa29ffb63350d2876b60c97c1e378aa6b75e459353f057c2f5e
7
- data.tar.gz: 4a120754c9dad45639f27e1b23ed44c84054440937ac1bfaccce508263090b84feb1175388867b12ded067b4ac936615e39d3490bdc0fe69b8e9447e7f7bb737
6
+ metadata.gz: ddff99a5c53edfb7a897b2c3015cbf883e1db67124df89d5c9cbe7058798cdc644f3954d575b6381ef017c458fa908df40bb14e825bb2ce174810f26844c4e24
7
+ data.tar.gz: ed3065454f356aaf82e325ae2e46bccafc8c93f39de9ccf99f7079b43bfab913231f4abfd355e437444e7d9d7268532e072c9b8447c782cd09f7079227fa83a1
data/lib/snails/mailer.rb CHANGED
@@ -12,32 +12,40 @@ module Snails
12
12
 
13
13
  @queue = :emails
14
14
 
15
- def initialize(opts)
16
- mail_config = (opts[:smtp] || opts[:mail]) or raise ":smtp options missing"
15
+ # class Bounce < StandardError; end
16
+ # class SoftBounce < Bounce; end
17
+ # class HardBounce < Bounce; end
18
+
19
+ def self.backends
20
+ {
21
+ 'test_backend' => 'Snails::Mailer::TestBackend',
22
+ 'smtp' => 'Snails::Mailer::TuktukBackend',
23
+ 'mailgun' => 'Snails::Mailer::MailgunBackend'
24
+ }
25
+ end
17
26
 
18
- if key = mail_config.dig(:dkim, :private_key) and File.exist?(key)
19
- mail_config[:dkim][:private_key] = IO.read(key)
20
- elsif mail_config[:dkim]
21
- puts "Private key for DKIM not found! Disabling..."
22
- mail_config.delete(:dkim)
23
- end
27
+ def self.init_backend(backend_name, opts = {})
28
+ backend_name = backend_name.presence || 'test_backend'
29
+ backends[backend_name].constantize.new(opts)
30
+ end
24
31
 
25
- Tuktuk.options = mail_config
26
- @debug = mail_config[:debug]
32
+ def initialize(opts)
27
33
  @from_email = opts[:from] or raise ":from required"
28
34
  @base_subject = opts[:base_subject] || ''
29
35
  @views = opts[:views] || Snails.root.join('lib', 'views')
30
36
  @logfile = opts[:logfile] # || Snails.root.join('log', 'mailer.log')
37
+
38
+ @backend = self.class.init_backend(opts[:backend_name], opts[:backend_options])
31
39
  end
32
40
 
33
41
  def email(name, &block)
34
42
  define_singleton_method(name) do |*args|
35
- instance_exec(*args, &block)
43
+ instance_exec(*args, &block)
36
44
  end
37
45
  end
38
46
 
39
47
  def helpers(&block)
40
- instance_eval(&block)
48
+ instance_eval(&block)
41
49
  end
42
50
 
43
51
  def perform(method, *args)
@@ -81,50 +89,143 @@ A <%= @exception.class %> occurred in <%= @url %>:
81
89
 
82
90
  private
83
91
 
84
- def render(view)
85
- template = File.read(File.join(@views, "#{view}.erb"))
92
+ def render(view_path, layout_path = nil)
93
+ view = File.read(File.join(@views, "#{view_path}.erb"))
94
+ if layout_path
95
+ layout = File.read(File.join(@views, "#{layout_path}.erb"))
96
+ render_erb(layout) { render_erb(view) }
97
+ else
98
+ render_erb(view)
99
+ end
100
+ end
101
+
102
+ def render_erb(template)
86
103
  ERB.new(template).result(binding)
87
104
  end
88
105
 
89
106
  def partial(name)
90
107
  partial_name = name.to_s["/"] ? name.to_s.reverse.sub("/", "_/").reverse : "_#{name}"
91
- render partial_name
108
+ render(partial_name)
92
109
  end
93
110
 
94
111
  def logger
95
112
  @logger ||= @logfile ? Logger.new(@logfile) : Snails.logger
96
113
  end
97
114
 
98
- def send_email(from: nil, to:, subject:, body: nil, template: nil, html_body: nil, html_template: nil, message_id: nil, return_path: nil, list_unsubscribe: nil)
115
+ def send_email(from: @from_email, to:, subject:, body: nil, template: nil, layout: nil, html_body: nil, html_template: nil, html_layout: nil, message_id: nil, attachments: nil, return_path: nil, list_unsubscribe: nil)
99
116
  raise "No recipient given for mail: #{subject}!" if to.blank?
100
117
 
101
118
  message = {
102
119
  to: to,
103
- from: from || @from_email,
104
- subject: @base_subject + subject
120
+ from: from,
121
+ subject: @base_subject + subject
105
122
  }
106
123
 
124
+ raise "Blank from" if message[:from].blank?
125
+ raise "Blank to" if message[:to].blank?
126
+
107
127
  if body or template
108
- message[:body] = template ? render(template) : body
128
+ message[:body] = template ? render(template, layout) : body
109
129
  end
110
130
 
111
131
  if html_body or html_template
112
- message[:html_body] = html_template ? render(html_template) : html_body
132
+ message[:html_body] = html_template ? render(html_template, html_layout) : html_body
113
133
  end
114
134
 
135
+ message[:attachments] = attachments if attachments
115
136
  message[:message_id] = message_id if message_id
116
137
  message[:return_path] = return_path if return_path
117
138
  message[:list_unsubscribe] = list_unsubscribe if list_unsubscribe
118
139
 
119
- logger.info "[#{to}] Delivering: #{subject}"
120
- debug = @debug.nil? ? !Snails.env.production? : @debug # if debug isn't set, determine based on env
121
- resp, email = Tuktuk.deliver(message, debug: debug)
140
+ logger.info "[#{to}] Delivering: #{subject}"
141
+ @backend.deliver(message)
142
+ end
143
+
144
+ alias_method :deliver, :send_email
145
+
146
+ class Backend
147
+ def deliver(email, options = {})
148
+ raise "Please redefine in subclass"
149
+ end
150
+
151
+ def deliver_many(emails, options = {})
152
+ emails.map { |e| deliver(e, options) }
153
+ end
154
+ end
155
+
156
+ class TestBackend < Backend
157
+ def initialize(opts = {})
158
+ end
159
+
160
+ def deliver(email, options = {})
161
+ puts "Deliverying single: #{email[:to]}"
162
+ end
163
+
164
+ def deliver_many(emails, options = {})
165
+ puts "Deliverying many: #{emails.count}"
166
+ end
167
+ end
168
+
169
+ class TuktukBackend < Backend
170
+ def initialize(config = {})
171
+ @debug = config[:debug]
172
+
173
+ puts "-- #{config.inspect}"
174
+
175
+ if key = config.dig(:dkim, :private_key) and File.exist?(key)
176
+ config[:dkim][:private_key] = IO.read(key)
177
+ elsif config[:dkim]
178
+ puts "Private key for DKIM not found! Disabling..."
179
+ config.delete(:dkim)
180
+ end
181
+
182
+ Tuktuk.options = config
183
+ end
184
+
185
+ def deliver(email, options = {})
186
+ debug = @debug.nil? ? !Snails.env.production? : @debug # if debug isn't set, determine based on env
187
+ resp, email = Tuktuk.deliver(email, debug: debug)
188
+
189
+ if resp.is_a?(Tuktuk::Bounce)
190
+ logger.info "[#{to}] Email bounced! [#{resp.code}] #{resp.message}"
191
+ end
192
+
193
+ return resp, email
194
+ end
195
+
196
+ def deliver_many(emails, options = {})
197
+ Tuktuk.deliver_many(emails, options)
198
+ end
199
+ end
200
+
201
+ class MailgunBackend < Backend
202
+
203
+ def initialize(api_key:, domain_name:)
204
+ @key = api_key
205
+ @url = "https://api.mailgun.net/v3/#{domain_name}/messages"
206
+ end
207
+
208
+ def deliver(email, options = {})
209
+ raise "No body!" if email[:body].nil?
210
+
211
+ data = {
212
+ from: email[:from],
213
+ to: email[:to],
214
+ subject: email[:subject],
215
+ }
216
+
217
+ data[:text] = email[:body] if email[:body]
218
+ data[:html] = email[:html_body] if email[:html_body]
219
+
220
+ if data[:text].blank? && data[:html].blank?
221
+ raise ArgumentError, "Either text or html required"
222
+ end
122
223
 
123
- if resp.is_a?(Tuktuk::Bounce)
124
- logger.info "[#{to}] Email bounced! [#{resp.code}] #{resp.message}"
224
+ opts = { username: 'api', password: @key }
225
+ resp = Dagger.post(@url, data, opts)
226
+ resp.ok? ? [resp.data, data[:to]] : nil
125
227
  end
126
228
 
127
- return resp, email
128
229
  end
129
230
 
130
231
  end
data/snails.gemspec CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "snails"
6
- s.version = '0.4.2'
6
+ s.version = '0.5.0'
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ['Tomás Pollak']
9
9
  s.email = ['tomas@forkhq.com']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomás Pollak
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-05 00:00:00.000000000 Z
11
+ date: 2022-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler