mandrill_mailer 0.4.8 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NGRiMzhmYWE5ODUwOWQzZjIxODI4M2RlOWFkMGUzN2NlOTQ3N2JjMw==
4
+ ZjFiMmQwMDkwY2Y2MmEyOWQyNjIwNjZlNGEwZDk3ZGI3YTE4NTZiMw==
5
5
  data.tar.gz: !binary |-
6
- NjNjZmZkOWY1OWI3ZTUxN2IzMTBiOTg1ZDU4ZTk3ZDc1NzEwZTljMQ==
6
+ YTIxMzNmNjllMDkwN2E1NDhhMTAzMTM5YjJhMjFhYTAzNDJiNGUxYQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MGQ1MTgwNjk5NjAwZTEzZmEzNWE5MjQwM2QzYzg1Mjk5ODk3MGExNmJkYTRh
10
- ZjNhNGQ5NjI3ZDI5NjQwMmNkNWU5ZWIwYWI2ZDNjZTZlNjU5Nzg0NzEwMjdj
11
- Nzc3OWRhNDY4NmYxOTcwOTZiN2ZjNmI0YzU3Y2QyNzMxNWRmYzU=
9
+ YWNjOTFlZmIzNmU0MWVkZmIyMzU0YmZmNmI1NzlmZWUyZjM0ZGEyNWJlNzY1
10
+ NzBiMGY5ZDFkZjFiNzIwNDAxMmJjODEwOTc1N2FlYmYwMWI0Njc2NDM1NmRh
11
+ ZWYxZjBiYTllZWFhZDk4YzU1YWQ5YzIxNWZkNTAxNzIwZWYyOTk=
12
12
  data.tar.gz: !binary |-
13
- ZmVmYWY0MGFkM2Y1N2JjZWVlNTBhOGYyYjQzOTA5MzIyYjQwZjYyZmQ3MDQ4
14
- MzI3NmE0Yjc1OTBhMjgxYTFhYWRlY2UwMGZjNmRmMzNmYTc5MDU2ZmFjNzZk
15
- MTVkZmIxODM1YjljZmM0ZjM1NGMwYTk5OGZiZmFmMGFiODlkYWI=
13
+ OGIwMDk1NWE5OTNkN2JjYTZhZTZhNGY4ZWExNjUwODFmZDU3MjM5Nzc0OWQx
14
+ YWE2YWVmZWRjZDMwNDU0NDYyY2RkMzcyODVmOTllYmQyNmUzODU5ZTRkZGFh
15
+ MmQ3Zjg3MGNhYzI0MDk1MzY5YzNmNjY1NTgyZTYwN2JmNTU2Mjc=
@@ -1,3 +1,6 @@
1
+ # 0.4.9
2
+ - [FEATURE] Added support for the Mandrill Messages api by adding a MandrillMailer::Messenger class. Thanks @arthurtalkgoal
3
+
1
4
  # 0.4.8
2
5
  - [IMPROVEMENT] Add a to= setter to the template mailer
3
6
 
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:
@@ -2,6 +2,7 @@ require 'action_view'
2
2
  require 'mandrill_mailer/railtie'
3
3
  require 'mandrill_mailer/mock'
4
4
  require 'mandrill_mailer/template_mailer'
5
+ require 'mandrill_mailer/message_mailer'
5
6
  require 'mandrill_mailer/version'
6
7
 
7
8
  module MandrillMailer
@@ -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