mandrill_mailer 0.4.8 → 0.4.9
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.
- checksums.yaml +8 -8
- data/CHANGELOG.md +3 -0
- data/README.md +37 -0
- data/lib/mandrill_mailer.rb +1 -0
- data/lib/mandrill_mailer/core_mailer.rb +367 -0
- data/lib/mandrill_mailer/message_mailer.rb +212 -0
- data/lib/mandrill_mailer/template_mailer.rb +10 -233
- data/lib/mandrill_mailer/version.rb +1 -1
- data/spec/message_mailer_spec.rb +148 -0
- data/spec/template_mailer_spec.rb +65 -27
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZjFiMmQwMDkwY2Y2MmEyOWQyNjIwNjZlNGEwZDk3ZGI3YTE4NTZiMw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YTIxMzNmNjllMDkwN2E1NDhhMTAzMTM5YjJhMjFhYTAzNDJiNGUxYQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YWNjOTFlZmIzNmU0MWVkZmIyMzU0YmZmNmI1NzlmZWUyZjM0ZGEyNWJlNzY1
|
10
|
+
NzBiMGY5ZDFkZjFiNzIwNDAxMmJjODEwOTc1N2FlYmYwMWI0Njc2NDM1NmRh
|
11
|
+
ZWYxZjBiYTllZWFhZDk4YzU1YWQ5YzIxNWZkNTAxNzIwZWYyOTk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OGIwMDk1NWE5OTNkN2JjYTZhZTZhNGY4ZWExNjUwODFmZDU3MjM5Nzc0OWQx
|
14
|
+
YWE2YWVmZWRjZDMwNDU0NDYyY2RkMzcyODVmOTllYmQyNmUzODU5ZTRkZGFh
|
15
|
+
MmQ3Zjg3MGNhYzI0MDk1MzY5YzNmNjY1NTgyZTYwN2JmNTU2Mjc=
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -156,6 +156,43 @@ end
|
|
156
156
|
|
157
157
|
* `:send_at` - When this message should be sent
|
158
158
|
|
159
|
+
## Sending a message without template
|
160
|
+
Sending a message without template is similar to sending a template one:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
class InvitationMailer < MandrillMailer::MessageMailer
|
164
|
+
default from: 'support@example.com'
|
165
|
+
|
166
|
+
def invite(invitation)
|
167
|
+
# in this example `invitation.invitees` is an Array
|
168
|
+
invitees = invitation.invitees.map { |invitee| { email: invitee.email, name: invitee.name } }
|
169
|
+
|
170
|
+
# no need to set up tempalte and template_content attributes, set up the html and text directly
|
171
|
+
mandrill_mail subject: I18n.t('invitation_mailer.invite.subject'),
|
172
|
+
to: invitees,
|
173
|
+
# to: invitation.email,
|
174
|
+
# to: { email: invitation.email, name: 'Honored Guest' },
|
175
|
+
text: "Example text content",
|
176
|
+
html: "<p>Example HTML content</p>",
|
177
|
+
view_content_link: "http://www.nba.com",
|
178
|
+
vars: {
|
179
|
+
'OWNER_NAME' => invitation.owner_name,
|
180
|
+
'PROJECT_NAME' => invitation.project_name
|
181
|
+
},
|
182
|
+
important: true,
|
183
|
+
inline_css: true,
|
184
|
+
recipient_vars: invitation.invitees.map do |invitee| # invitation.invitees is an Array
|
185
|
+
{ invitee.email =>
|
186
|
+
{
|
187
|
+
'INVITEE_NAME' => invitee.name,
|
188
|
+
'INVITATION_URL' => new_invitation_url(invitee.email, secret: invitee.secret_code)
|
189
|
+
}
|
190
|
+
}
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
159
196
|
## Sending an email
|
160
197
|
|
161
198
|
You can send the email by using the familiar syntax:
|
data/lib/mandrill_mailer.rb
CHANGED
@@ -0,0 +1,367 @@
|
|
1
|
+
# MandrilMailer class for sending transactional emails through mandril.
|
2
|
+
# Only template based emails are supported at this time.
|
3
|
+
|
4
|
+
# Example usage:
|
5
|
+
|
6
|
+
# class InvitationMailer < MandrillMailer::TemplateMailer
|
7
|
+
# default from: 'support@codeschool.com'
|
8
|
+
|
9
|
+
# def invite(invitation)
|
10
|
+
# invitees = invitation.invitees.map { |invitee| { email: invitee.email, name: invitee.name } }
|
11
|
+
#
|
12
|
+
# mandrill_mail template: 'Group Invite',
|
13
|
+
# subject: I18n.t('invitation_mailer.invite.subject'),
|
14
|
+
# to: invitees,
|
15
|
+
# # to: invitation.email
|
16
|
+
# # to: { email: invitation.email, name: invitation.recipient_name }
|
17
|
+
# vars: {
|
18
|
+
# 'OWNER_NAME' => invitation.owner_name,
|
19
|
+
# 'PROJECT_NAME' => invitation.project_name
|
20
|
+
# },
|
21
|
+
# recipient_vars: invitation.invitees.map do |invitee| # invitation.invitees is an Array
|
22
|
+
# { invitee.email =>
|
23
|
+
# {
|
24
|
+
# 'INVITEE_NAME' => invitee.name,
|
25
|
+
# 'INVITATION_URL' => new_invitation_url(invitee.email, secret: invitee.secret_code)
|
26
|
+
# }
|
27
|
+
# }
|
28
|
+
# end,
|
29
|
+
# template_content: {},
|
30
|
+
# attachments: [{file: File.read(File.expand_path('assets/some_image.png')), filename: 'My Image.png', mimetype: 'image/png'}],
|
31
|
+
# important: true,
|
32
|
+
# inline_css: true
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
|
36
|
+
# #default:
|
37
|
+
# :from - set the default from email address for the mailer
|
38
|
+
|
39
|
+
# .mandrill_mail
|
40
|
+
# :template(required) - Template name from within Mandrill
|
41
|
+
|
42
|
+
# :subject(required) - Subject of the email
|
43
|
+
|
44
|
+
# :to(required) - Accepts an email String, a Hash with :name and :email keys
|
45
|
+
# or an Array of Hashes with :name and :email keys
|
46
|
+
# examples:
|
47
|
+
# 1)
|
48
|
+
# 'example@domain.com`
|
49
|
+
# 2)
|
50
|
+
# { email: 'someone@email.com', name: 'Bob Bertly' }
|
51
|
+
# 3)
|
52
|
+
# [{ email: 'someone@email.com', name: 'Bob Bertly' },
|
53
|
+
# { email: 'other@email.com', name: 'Claire Nayo' }]
|
54
|
+
#
|
55
|
+
|
56
|
+
# :vars - A Hash of merge tags made available to the email. Use them in the
|
57
|
+
# email by wrapping them in '*||*' vars: {'OWNER_NAME' => 'Suzy'} is used
|
58
|
+
# by doing: *|OWNER_NAME|* in the email template within Mandrill
|
59
|
+
#
|
60
|
+
# :recipient_vars - Similar to :vars, this is a Hash of merge tags specific to a particular recipient.
|
61
|
+
# Use this if you are sending batch transactions and hence need to send multiple emails at one go.
|
62
|
+
# ex. [{'someone@email.com' => {'INVITEE_NAME' => 'Roger'}}, {'another@email.com' => {'INVITEE_NAME' => 'Tommy'}}]
|
63
|
+
|
64
|
+
# :template_content - A Hash of values and content for Mandrill editable content blocks.
|
65
|
+
# In MailChimp templates there are editable regions with 'mc:edit' attributes that look
|
66
|
+
# a little like: '<div mc:edit="header">My email content</div>' You can insert content directly into
|
67
|
+
# these fields by passing a Hash {'header' => 'my email content'}
|
68
|
+
|
69
|
+
# :attachments - An array of file objects with the following keys:
|
70
|
+
# file: This is the actual file, it will be converted to byte data in the mailer
|
71
|
+
# filename: The name of the file
|
72
|
+
# mimetype: This is the mimetype of the file. Ex. png = image/png, pdf = application/pdf, txt = text/plain etc
|
73
|
+
|
74
|
+
# :images - An array of embedded images to add to the message:
|
75
|
+
# file: This is the actual file, it will be converted to byte data in the mailer
|
76
|
+
# filename: The Content ID of the image - use <img src="cid:THIS_VALUE"> to reference the image in your HTML content
|
77
|
+
# mimetype: The MIME type of the image - must start with "image/"
|
78
|
+
|
79
|
+
# :headers - Extra headers to add to the message (currently only Reply-To and X-* headers are allowed) {"...": "..."}
|
80
|
+
|
81
|
+
# :bcc - Add an email to bcc to
|
82
|
+
|
83
|
+
# :tags - Array of Strings to tag the message with. Stats are
|
84
|
+
# accumulated using tags, though we only store the first 100 we see,
|
85
|
+
# so this should not be unique or change frequently. Tags should be
|
86
|
+
# 50 characters or less. Any tags starting with an underscore are
|
87
|
+
# reserved for internal use and will cause errors.
|
88
|
+
|
89
|
+
# :google_analytics_domains - Array of Strings indicating for which any
|
90
|
+
# matching URLs will automatically have Google Analytics parameters appended
|
91
|
+
# to their query string automatically.
|
92
|
+
|
93
|
+
# :google_analytics_campaign - String indicating the value to set for
|
94
|
+
# the utm_campaign tracking parameter. If this isn't provided the email's
|
95
|
+
# from address will be used instead.
|
96
|
+
|
97
|
+
# :inline_css - whether or not to automatically inline all CSS styles provided in the
|
98
|
+
# message HTML - only for HTML documents less than 256KB in size
|
99
|
+
|
100
|
+
# :important - whether or not this message is important, and should be delivered ahead of non-important messages
|
101
|
+
require 'base64'
|
102
|
+
|
103
|
+
module MandrillMailer
|
104
|
+
class CoreMailer
|
105
|
+
# include Rails.application.routes.url_helpers
|
106
|
+
include ActionView::Helpers::NumberHelper
|
107
|
+
|
108
|
+
class InvalidEmail < StandardError; end
|
109
|
+
class InvalidMailerMethod < StandardError; end
|
110
|
+
class InvalidInterceptorParams < StandardError; end
|
111
|
+
|
112
|
+
# Public: Other information on the message to send
|
113
|
+
attr_accessor :message
|
114
|
+
|
115
|
+
# Public: Enable background sending mode
|
116
|
+
attr_accessor :async
|
117
|
+
|
118
|
+
# Public: Name of the dedicated IP pool that should be used to send the message
|
119
|
+
attr_accessor :ip_pool
|
120
|
+
|
121
|
+
# Public: When message should be sent
|
122
|
+
attr_accessor :send_at
|
123
|
+
|
124
|
+
# Public: Defaults for the mailer. Currently the only option is from:
|
125
|
+
#
|
126
|
+
# options - The Hash options used to refine the selection (default: {}):
|
127
|
+
# :from - Default from email address
|
128
|
+
#
|
129
|
+
# Examples
|
130
|
+
#
|
131
|
+
# default from: 'foo@bar.com'
|
132
|
+
#
|
133
|
+
# Returns options
|
134
|
+
def self.defaults
|
135
|
+
@defaults || super_defaults
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.super_defaults
|
139
|
+
superclass.defaults if superclass.respond_to?(:defaults)
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.default(args)
|
143
|
+
@defaults ||= {}
|
144
|
+
@defaults[:from] ||= 'example@email.com'
|
145
|
+
@defaults.merge!(args)
|
146
|
+
end
|
147
|
+
|
148
|
+
class << self
|
149
|
+
attr_writer :defaults
|
150
|
+
end
|
151
|
+
|
152
|
+
# Public: setup a way to test mailer methods
|
153
|
+
#
|
154
|
+
# mailer_method - Name of the mailer method the test setup is for
|
155
|
+
#
|
156
|
+
# block - Block of code to execute to perform the test. The mailer
|
157
|
+
# and options are passed to the block. The options have to
|
158
|
+
# contain at least the :email to send the test to.
|
159
|
+
#
|
160
|
+
# Examples
|
161
|
+
#
|
162
|
+
# test_setup_for :invite do |mailer, options|
|
163
|
+
# invitation = OpenStruct.new({
|
164
|
+
# email: options[:email],
|
165
|
+
# owner_name: 'foobar',
|
166
|
+
# secret: rand(9000000..1000000).to_s
|
167
|
+
# })
|
168
|
+
# mailer.invite(invitation).deliver
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
# Returns the duplicated String.
|
172
|
+
def self.test_setup_for(mailer_method, &block)
|
173
|
+
@mailer_methods ||= {}
|
174
|
+
@mailer_methods[mailer_method] = block
|
175
|
+
end
|
176
|
+
|
177
|
+
# Public: Executes a test email
|
178
|
+
#
|
179
|
+
# mailer_method - Method to execute
|
180
|
+
#
|
181
|
+
# options - The Hash options used to refine the selection (default: {}):
|
182
|
+
# :email - The email to send the test to.
|
183
|
+
#
|
184
|
+
# Examples
|
185
|
+
#
|
186
|
+
# InvitationMailer.test(:invite, email: 'benny@envylabs.com')
|
187
|
+
#
|
188
|
+
# Returns the duplicated String.
|
189
|
+
def self.test(mailer_method, options={})
|
190
|
+
unless options[:email]
|
191
|
+
raise InvalidEmail.new 'Please specify a :email option(email to send the test to)'
|
192
|
+
end
|
193
|
+
|
194
|
+
if @mailer_methods[mailer_method]
|
195
|
+
@mailer_methods[mailer_method].call(self.new, options)
|
196
|
+
else
|
197
|
+
raise InvalidMailerMethod.new "The mailer method: #{mailer_method} does not have test setup"
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
# Public: Triggers the stored Mandrill params to be sent to the Mandrill api
|
203
|
+
def deliver
|
204
|
+
mesg = "#{self.class.name}#deliver() is not implemented."
|
205
|
+
raise NotImplementedError.new(mesg)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Public: Build the hash needed to send to the mandrill api
|
209
|
+
#
|
210
|
+
# args - The Hash options used to refine the selection:
|
211
|
+
|
212
|
+
# Examples
|
213
|
+
#
|
214
|
+
# mandrill_mail template: 'Group Invite',
|
215
|
+
# subject: I18n.t('invitation_mailer.invite.subject'),
|
216
|
+
# to: invitation.email,
|
217
|
+
# vars: {
|
218
|
+
# 'OWNER_NAME' => invitation.owner_name,
|
219
|
+
# 'INVITATION_URL' => new_invitation_url(email: invitation.email, secret: invitation.secret)
|
220
|
+
# }
|
221
|
+
#
|
222
|
+
# Returns the the mandrill mailer class (this is so you can chain #deliver like a normal mailer)
|
223
|
+
def mandrill_mail(args)
|
224
|
+
mesg = "#{self.class.name}#mandrill_mail() is not implemented."
|
225
|
+
raise NotImplementedError.new(mesg)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Public: Data hash (deprecated)
|
229
|
+
def data
|
230
|
+
mesg = "#{self.class.name}#data() is not implemented."
|
231
|
+
raise NotImplementedError.new(mesg)
|
232
|
+
end
|
233
|
+
|
234
|
+
def check_required_options
|
235
|
+
mesg = "#{self.class.name}#check_required_options() is not implemented."
|
236
|
+
raise NotImplementedError.new(mesg)
|
237
|
+
end
|
238
|
+
|
239
|
+
def from
|
240
|
+
self.message && self.message['from_email']
|
241
|
+
end
|
242
|
+
|
243
|
+
def to
|
244
|
+
self.message && self.message['to']
|
245
|
+
end
|
246
|
+
|
247
|
+
def to=(values)
|
248
|
+
self.message && self.message['to'] = format_to_params(values)
|
249
|
+
end
|
250
|
+
|
251
|
+
def bcc
|
252
|
+
self.message && self.message['bcc_address']
|
253
|
+
end
|
254
|
+
|
255
|
+
protected
|
256
|
+
|
257
|
+
def mandrill_attachment_args(args)
|
258
|
+
return unless args
|
259
|
+
args.map do |attachment|
|
260
|
+
attachment.symbolize_keys!
|
261
|
+
type = attachment[:mimetype]
|
262
|
+
name = attachment[:filename]
|
263
|
+
file = attachment[:file]
|
264
|
+
{"type" => type, "name" => name, "content" => Base64.encode64(file)}
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def mandrill_images_args(args)
|
269
|
+
return unless args
|
270
|
+
args.map do |attachment|
|
271
|
+
attachment.symbolize_keys!
|
272
|
+
type = attachment[:mimetype]
|
273
|
+
name = attachment[:filename]
|
274
|
+
file = attachment[:file]
|
275
|
+
{"type" => type, "name" => name, "content" => Base64.encode64(file)}
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Makes this class act as a singleton without it actually being a singleton
|
280
|
+
# This keeps the syntax the same as the orginal mailers so we can swap quickly if something
|
281
|
+
# goes wrong.
|
282
|
+
def self.method_missing(method, *args)
|
283
|
+
return super unless respond_to?(method)
|
284
|
+
new.method(method).call(*args)
|
285
|
+
end
|
286
|
+
|
287
|
+
def self.respond_to?(method, include_private = false)
|
288
|
+
super || instance_methods.include?(method.to_sym)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Proxy route helpers to rails if Rails exists. Doing routes this way
|
292
|
+
# makes it so this gem doesn't need to be a rails engine
|
293
|
+
def method_missing(method, *args)
|
294
|
+
return super unless defined?(Rails) && Rails.application.routes.url_helpers.respond_to?(method)
|
295
|
+
# Check to see if one of the args is an open struct. If it is, we'll assume it's the
|
296
|
+
# test stub and try to call a path or url attribute.
|
297
|
+
if args.any? {|arg| arg.kind_of?(MandrillMailer::Mock)}
|
298
|
+
# take the first OpenStruct found in args and look for .url or.path
|
299
|
+
args.each do |arg|
|
300
|
+
if arg.kind_of?(MandrillMailer::Mock)
|
301
|
+
break arg.url || arg.path
|
302
|
+
end
|
303
|
+
end
|
304
|
+
else
|
305
|
+
options = args.extract_options!.merge({host: MandrillMailer.config.default_url_options[:host], protocol: MandrillMailer.config.default_url_options[:protocol]})
|
306
|
+
args << options
|
307
|
+
Rails.application.routes.url_helpers.method(method).call(*args)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def image_path(image)
|
312
|
+
if defined? Rails
|
313
|
+
ActionController::Base.helpers.asset_path(image)
|
314
|
+
else
|
315
|
+
method_missing(:image_path, image)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def image_url(image)
|
320
|
+
"#{root_url}#{image_path(image).split('/').reject!(&:empty?).join('/')}"
|
321
|
+
end
|
322
|
+
|
323
|
+
# convert a normal hash into the format mandrill needs
|
324
|
+
def mandrill_args(args)
|
325
|
+
return [] unless args
|
326
|
+
args.map do |k,v|
|
327
|
+
{'name' => k, 'content' => v}
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def mandrill_rcpt_args(args)
|
332
|
+
return [] unless args
|
333
|
+
args.map do |item|
|
334
|
+
rcpt = item.keys[0]
|
335
|
+
{'rcpt' => rcpt, 'vars' => mandrill_args(item.fetch(rcpt))}
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
# ensure only true or false is returned given arg
|
340
|
+
def format_boolean(arg)
|
341
|
+
arg ? true : false
|
342
|
+
end
|
343
|
+
|
344
|
+
# handle if to params is an array of either hashes or strings or the single string
|
345
|
+
def format_to_params(to_params)
|
346
|
+
if to_params.kind_of? Array
|
347
|
+
to_params.map do |p|
|
348
|
+
to_params_item(p)
|
349
|
+
end
|
350
|
+
else
|
351
|
+
[to_params_item(to_params)]
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
# single to params item
|
356
|
+
def to_params_item(item)
|
357
|
+
return {"email" => item, "name" => item} unless item.kind_of? Hash
|
358
|
+
item
|
359
|
+
end
|
360
|
+
|
361
|
+
def api_key
|
362
|
+
MandrillMailer.config.api_key
|
363
|
+
end
|
364
|
+
|
365
|
+
|
366
|
+
end
|
367
|
+
end
|