snails 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/snails/mailer.rb +127 -26
- data/snails.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06b4aea8ffe430adc00748ea5f48ace43cd79fdf26cebb02da08b31ea88765ac
|
4
|
+
data.tar.gz: 9c856ce125123fe7d3423b362ea948dba6b41038490dea3b0158084ecf2d6b35
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
16
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
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(
|
85
|
-
|
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
|
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:
|
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
|
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
|
-
|
121
|
-
|
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
|
-
|
124
|
-
|
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
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
|
+
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:
|
11
|
+
date: 2022-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|