postmark 0.9.19 → 1.0.0

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 (41) hide show
  1. data/.travis.yml +8 -0
  2. data/CHANGELOG.rdoc +20 -0
  3. data/Gemfile +6 -0
  4. data/README.md +351 -91
  5. data/VERSION +1 -1
  6. data/lib/postmark.rb +40 -132
  7. data/lib/postmark/api_client.rb +162 -0
  8. data/lib/postmark/bounce.rb +20 -17
  9. data/lib/postmark/handlers/mail.rb +10 -3
  10. data/lib/postmark/helpers/hash_helper.rb +35 -0
  11. data/lib/postmark/helpers/message_helper.rb +62 -0
  12. data/lib/postmark/http_client.rb +44 -28
  13. data/lib/postmark/inbound.rb +21 -0
  14. data/lib/postmark/inflector.rb +28 -0
  15. data/lib/postmark/message_extensions/mail.rb +50 -5
  16. data/lib/postmark/message_extensions/shared.rb +23 -28
  17. data/lib/postmark/version.rb +1 -1
  18. data/postmark.gemspec +4 -7
  19. data/spec/data/empty.gif +0 -0
  20. data/spec/integration/api_client_hashes_spec.rb +101 -0
  21. data/spec/integration/api_client_messages_spec.rb +127 -0
  22. data/spec/integration/mail_delivery_method_spec.rb +80 -0
  23. data/spec/spec_helper.rb +15 -5
  24. data/spec/support/helpers.rb +11 -0
  25. data/spec/{shared_examples.rb → support/shared_examples.rb} +0 -0
  26. data/spec/unit/postmark/api_client_spec.rb +246 -0
  27. data/spec/unit/postmark/bounce_spec.rb +142 -0
  28. data/spec/unit/postmark/handlers/mail_spec.rb +39 -0
  29. data/spec/unit/postmark/helpers/hash_helper_spec.rb +34 -0
  30. data/spec/unit/postmark/helpers/message_helper_spec.rb +115 -0
  31. data/spec/unit/postmark/http_client_spec.rb +204 -0
  32. data/spec/unit/postmark/inbound_spec.rb +88 -0
  33. data/spec/unit/postmark/inflector_spec.rb +35 -0
  34. data/spec/unit/postmark/json_spec.rb +37 -0
  35. data/spec/unit/postmark/message_extensions/mail_spec.rb +205 -0
  36. data/spec/unit/postmark_spec.rb +164 -0
  37. metadata +45 -93
  38. data/lib/postmark/attachments_fix_for_mail.rb +0 -48
  39. data/lib/postmark/message_extensions/tmail.rb +0 -115
  40. data/spec/bounce_spec.rb +0 -53
  41. data/spec/postmark_spec.rb +0 -253
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.8.7"
4
+ - "1.9.2"
5
+ - "1.9.3"
6
+ - "2.0.0"
7
+ - "jruby-19mode"
8
+ script: bundle exec rake spec
@@ -1,5 +1,25 @@
1
1
  = Changelog
2
2
 
3
+ == 1.0.0
4
+
5
+ * Introduced new instance-based architecture (see README for more details).
6
+ * Removed TMail support.
7
+ * Added support for sending emails in batches.
8
+ * Added API to send emails without Mail library.
9
+ * Introduced lock-free approach for Mail::Postmark delivery method.
10
+ * Deprecated the Mail::Message#postmark_attachments method
11
+ * Added Postmark::Inbound module.
12
+ * Added integration tests.
13
+ * Added support for the "server" endpoint of the Postmark API.
14
+ * Improved unit test coverage.
15
+ * Added more examples to the README file.
16
+ * Added official JRuby support.
17
+ * Fixed the inconsistent behaviour of Mail::Message#tag method added by the gem.
18
+ * Added Mail::Message#delivered property and Mail::Message#delivered? predicate.
19
+ * Added Mail::Message#postmark_response method.
20
+ * Removed Postmark::AttachmentsFixForMail class (that hack no longer works).
21
+ * Added Travis-CI for integration tests.
22
+
3
23
  == 0.9.19
4
24
 
5
25
  * Added support for native attachments API provided by Ruby Mail library.
data/Gemfile CHANGED
@@ -2,3 +2,9 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in postmark.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem 'rspec', '~> 2.13.0'
8
+ gem 'fakeweb'
9
+ gem 'fakeweb-matcher'
10
+ end
data/README.md CHANGED
@@ -1,42 +1,315 @@
1
1
  # Postmark Gem
2
+ [![Build Status](https://travis-ci.org/wildbit/postmark-gem.png?branch=master)](https://travis-ci.org/wildbit/postmark-gem) [![Code Climate](https://codeclimate.com/github/wildbit/postmark-gem.png)](https://codeclimate.com/github/wildbit/postmark-gem)
2
3
 
3
- This gem is an official wrapper for [Postmark HTTP API](http://postmarkapp.com). Use it to send emails and retrieve info about bounces.
4
+ This gem is the official wrapper for the [Postmark HTTP API](http://postmarkapp.com). Postmark allows you to send your application's emails with high delivery rates, including bounce/spam processing and detailed statistics. In addition, Postmark can parse incoming emails which are forwarded back to your application.
4
5
 
5
- ## Getting Started
6
+ ## Install the gem
6
7
 
7
- ### Install the gem
8
+ With Bundler:
8
9
 
9
- ``` bash
10
- gem install postmark
10
+ ``` ruby
11
+ gem 'postmark'
11
12
  ```
12
13
 
13
- ### Install [Mail](http://rubygems.org/gems/mail) library
14
-
15
- In addition to the `postmark` gem you also need to install `mail` gem.
14
+ Without Bundler:
16
15
 
17
16
  ``` bash
18
- gem install mail
17
+ gem install postmark
19
18
  ```
20
19
 
21
- You can also use the gem with `tmail` library. This is not recommended for any
22
- new projects, but may be useful for legacy Ruby 1.8.7 projects.
23
-
24
- ### Get Postmark API key
20
+ ## Get a Postmark API key
25
21
 
26
22
  In order to send emails using Postmark ruby gem, you will need a
27
23
  [Postmark](http://postmarkapp.com) account. If you don't have one please
28
24
  register at https://postmarkapp.com/sign_up.
29
25
 
30
- If you didn't create any servers yet, please create one, proceed to
26
+ If you didnt create any servers yet, please create one, proceed to the
31
27
  `Credentials` tab and copy an API key. API keys should be frequently rotated for
32
28
  security reasons.
33
29
 
34
- ## Using with [Mail](http://rubygems.org/gems/mail) library
30
+ ## Communicating with the API
35
31
 
36
32
  Make sure you have a [sender signature](https://postmarkapp.com/signatures) for
37
- every From email you specify. From can also accept array of addresses.
33
+ every From email address you specify.
34
+
35
+ Create an instance of `Postmark::ApiClient` to start sending emails.
36
+
37
+ ``` ruby
38
+ your_api_key = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
39
+ client = Postmark::ApiClient.new(your_api_key)
40
+ ```
41
+
42
+ `Postmark::ApiClient` accepts various options:
43
+
44
+ ``` ruby
45
+ client = Postmark::ApiClient.new(your_api_key, secure: true
46
+ http_open_timeout: 15)
47
+ ```
48
+
49
+ Some useful options are:
50
+
51
+ * `secure` (`true` or `false`): set to true to use SSL connection.
52
+ * `http_read_timeout` (positive number): limit HTTP read time to `n` seconds.
53
+ * `http_open_timeout` (positive number): limit HTTP open time to `n` seconds.
54
+ * `proxy_host` (string): proxy address to use.
55
+ * `proxy_port` (positive number): proxy port to use.
56
+ * `proxy_user` (string): proxy user.
57
+ * `proxy_pass` (string): proxy password.
58
+
59
+ ## Sending a plain text message
60
+
61
+ ``` ruby
62
+ client.deliver(from: 'sheldon@bigbangtheory.com',
63
+ to: 'Leonard Hofstadter <leonard@bigbangtheory.com>',
64
+ subject: 'Re: Come on, Sheldon. It will be fun.',
65
+ text_body: 'That\'s what you said about the Green Lantern ' \
66
+ 'movie. You were 114 minutes of wrong.')
67
+ # => {:to=>"Leonard Hofstadter <leonard@bigbangtheory.com>", :submitted_at=>"2013-05-09T02:45:16.2059023-04:00", :message_id=>"b2b268e3-6a70-xxxx-b897-49c9eb8b1d2e", :error_code=>0, :message=>"OK"}
68
+ ```
69
+
70
+ ## Sending an HTML message
71
+
72
+ ``` ruby
73
+ client.deliver(from: 'sheldon@bigbangtheory.com',
74
+ to: 'Leonard Hofstadter <leonard@bigbangtheory.com>',
75
+ subject: 'Re: What, to you, is a large crowd?',
76
+ html_body: '<p>Any group big enough to trample me to death. ' \
77
+ 'General rule of thumb is 36 adults or 70 ' \
78
+ 'children.</p>')
79
+ # => {:to=>"Leonard Hofstadter <leonard@bigbangtheory.com>", :submitted_at=>"2013-05-09T02:51:08.8789433-04:00", :message_id=>"75c28987-564e-xxxx-b6eb-e8071873ac06", :error_code=>0, :message=>"OK"}
80
+ ```
81
+
82
+ ## Sending a message with attachments
83
+
84
+ You can add
85
+ [attachments](http://developer.postmarkapp.com/developer-build.html#attachments)
86
+ to your messages. Keep in mind message size limit (contents and attachment) is currently 10 MB.
87
+
88
+ ``` ruby
89
+ client.deliver(from: 'leonard@bigbangtheory.com',
90
+ to: 'Dr. Sheldon Cooper <sheldon@bigbangtheory.com>',
91
+ subject: 'Have you seen these pictures of yours?',
92
+ text_body: 'You look like a real geek!',
93
+ attachments: [File.open('1.jpeg'),
94
+ {name: 'sheldon.jpeg',
95
+ content: [File.read('2.jpeg')].pack('m'),
96
+ content_type: 'image/jpeg'}])
97
+ # => {:to=>"Dr. Sheldon Cooper <sheldon@bigbangtheory.com>", :submitted_at=>"2013-05-09T02:56:12.2828813-04:00", :message_id=>"8ec0d283-8b93-xxxx-9d65-241d1777cf0f", :error_code=>0, :message=>"OK"}
98
+ ```
99
+
100
+ ## Sending a multipart message
101
+
102
+ ``` ruby
103
+ client.deliver(from: 'sheldon@bigbangtheory.com',
104
+ to: 'Leonard Hofstadter <leonard@bigbangtheory.com>',
105
+ subject: 'Re: Anything Can Happen Thursday',
106
+ text_body: 'Apparently the news didn\'t reach my digestive ' \
107
+ 'system, which when startled has it\'s own version ' \
108
+ 'of "Anything Can Happen Thursday"',
109
+ html_body: '<p>Apparently the news didn&rsquo;t reach my ' \
110
+ 'digestive system, which when startled has ' \
111
+ 'it&rsquo;s own version of &ldquo;Anything Can '\
112
+ 'Happen Thursday&rdquo;</p>')
113
+ # => {:to=>"Leonard Hofstadter <leonard@bigbangtheory.com>", :submitted_at=>"2013-05-09T02:58:00.089828-04:00", :message_id=>"bc973458-1315-xxxx-b295-6aa0a2b631ac", :error_code=>0, :message=>"OK"}
114
+ ```
115
+
116
+ ## Tagging messages
117
+
118
+ You can categorize outgoing email using the optional `:tag` property. If you use
119
+ different tags for the different types of emails your application generates,
120
+ you will be able to get detailed statistics for them through the Postmark user
121
+ interface.
122
+
123
+ ``` ruby
124
+ client.deliver(from: 'sheldon@bigbangtheory.com',
125
+ to: 'Penny <penny@bigbangtheory.com>',
126
+ subject: 'Re: You cleaned my apartment???',
127
+ text_body: 'I couldn\'t sleep knowing that just outside my ' \
128
+ 'bedroom is our living room and just outside our ' \
129
+ 'living room is that hallway and immediately adjacent ' \
130
+ 'to that hallway is this!',
131
+ tag: 'confidential')
132
+
133
+ # => {:to=>"Penny <penny@bigbangtheory.com>", :submitted_at=>"2013-05-09T03:00:55.4454938-04:00", :message_id=>"34aed4b3-3a95-xxxx-bd1d-88064909cc93", :error_code=>0, :message=>"OK"}
134
+ ```
135
+
136
+ ## Sending to multiple recipients
137
+
138
+ You can pass multiple recipient addresses in the `:to` field and the optional
139
+ `:cc` and `:bcc` fields. Note that Postmark has a limit of twenty recipients
140
+ per message in total. You need to take care not to exceed that limit.
141
+ Otherwise, you will get an error.
142
+
143
+ ``` ruby
144
+ client.deliver(from: 'sheldon@bigbangtheory.com',
145
+ to: ['Leonard Hofstadter <leonard@bigbangtheory.com>',
146
+ 'Penny <penny@bigbangtheory.com>'],
147
+ cc: ['Dr. Koothrappali <raj@bigbangtheory.com>'],
148
+ bcc: 'secretsheldonstorage@bigbangtheory.com',
149
+ subject: 'Re: Come on, Sheldon. It will be fun.',
150
+ text_body: 'That\'s what you said about the Green Lantern ' \
151
+ 'movie. You were 114 minutes of wrong.')
152
+ # => {:to=>"Leonard Hofstadter <leonard@bigbangtheory.com>, Penny <penny@bigbangtheory.com>", :submitted_at=>"2013-05-09T05:04:16.3247488-04:00", :message_id=>"d647c5d6-xxxx-466d-9411-557dcd5c2297", :error_code=>0, :message=>"OK"}
153
+ ```
154
+
155
+ ## Sending in batches
156
+
157
+ While Postmark is focused on transactional email, we understand that developers
158
+ with higher volumes or processing time constraints need to send their messages
159
+ in batches. To facilitate this we provide a batching endpoint that permits you
160
+ to send up to 500 well-formed Postmark messages in a single API call.
161
+
162
+ ``` ruby
163
+ messages = []
164
+
165
+ messages << {from: 'sheldon@bigbangtheory.com',
166
+ to: 'Leonard Hofstadter <leonard@bigbangtheory.com>',
167
+ subject: 'Re: Come on, Sheldon. It will be fun.',
168
+ text_body: 'That\'s what you said about the Green Lantern ' \
169
+ 'movie. You were 114 minutes of wrong.'}
170
+
171
+ messages << {from: 'sheldon@bigbangtheory.com',
172
+ to: 'Penny <penny@bigbangtheory.com>',
173
+ subject: 'Re: You cleaned my apartment???',
174
+ text_body: 'I couldn\'t sleep knowing that just outside my ' \
175
+ 'bedroom is our living room and just outside our ' \
176
+ 'living room is that hallway and immediately ' \
177
+ 'adjacent to that hallway is this!',
178
+ tag: 'confidential'}
179
+
180
+ client.deliver_in_batches(messages)
181
+ # => [{:to=>"Leonard Hofstadter <leonard@bigbangtheory.com>", :submitted_at=>"2013-05-09T05:19:16.3361118-04:00", :message_id=>"247e43a9-6b0d-4914-a87f-7b74bf76b5cb", :error_code=>0, :message=>"OK"}, {:to=>"Penny <penny@bigbangtheory.com>", :submitted_at=>"2013-05-09T05:19:16.3517099-04:00", :message_id=>"26467642-f169-4da8-87a8-b89154067dfb", :error_code=>0, :message=>"OK"}]
182
+ ```
183
+
184
+ ## Parsing inbound
185
+
186
+ Inbound processing allows you (or your users) to send emails to Postmark, which we then
187
+ process and deliver to you via a web hook in a nicely formatted JSON document.
188
+
189
+ Here is a simple Ruby/Sinatra application that does basic inbound processing.
190
+
191
+ ``` ruby
192
+ logger = Logger.new(STDOUT)
193
+
194
+ class Comment
195
+ attr_accessor :attributes
196
+
197
+ def self.create_from_inbound_hook(message)
198
+ self.new(:text => message["TextBody"],
199
+ :user_email => message["From"],
200
+ :discussion_id => message["MailboxHash"])
201
+ end
202
+
203
+ def initialize(attributes={})
204
+ @attributes = attributes
205
+ end
206
+ end
207
+
208
+ post '/inbound' do
209
+ request.body.rewind
210
+ comment = Comment.create_from_inbound_hook(Postmark::Json.decode(request.body.read))
211
+ logger.info comment.inspect
212
+ end
213
+ ```
214
+
215
+ If you don’t like that the fields of the Inbound JSON document are all in CamelCase, you
216
+ can use the `Postmark::Inbound.to_ruby_hash` method to give it some Ruby flavor.
217
+
218
+ ```
219
+ postmark_hash = Postmark::Json.decode(request.body.read)
220
+ ruby_hash = Postmark::Inbound.to_ruby_hash(postmark_hash)
221
+ # => {:from=>"myUser@theirDomain.com", :from_full=>{:email=>"myUser@theirDomain.com", :name=>"John Doe"}, :to=>"451d9b70cf9364d23ff6f9d51d870251569e+ahoy@inbound.postmarkapp.com", :to_full=>[{:email=>"451d9b70cf9364d23ff6f9d51d870251569e+ahoy@inbound.postmarkapp.com", :name=>""}], :cc=>"\"Full name\" <sample.cc@emailDomain.com>, \"Another Cc\" <another.cc@emailDomain.com>", :cc_full=>[{:email=>"sample.cc@emailDomain.com", :name=>"Full name"}, {:email=>"another.cc@emailDomain.com", :name=>"Another Cc"}], :reply_to=>"myUsersReplyAddress@theirDomain.com", :subject=>"This is an inbound message", :message_id=>"22c74902-a0c1-4511-804f2-341342852c90", :date=>"Thu, 5 Apr 2012 16:59:01 +0200", :mailbox_hash=>"ahoy", :text_body=>"[ASCII]", :html_body=>"[HTML(encoded)]", :tag=>"", :headers=>[{:name=>"X-Spam-Checker-Version", :value=>"SpamAssassin 3.3.1 (2010-03-16) onrs-ord-pm-inbound1.wildbit.com"}, {:name=>"X-Spam-Status", :value=>"No"}, {:name=>"X-Spam-Score", :value=>"-0.1"}, {:name=>"X-Spam-Tests", :value=>"DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_PASS"}, {:name=>"Received-SPF", :value=>"Pass (sender SPF authorized) identity=mailfrom; client-ip=209.85.160.180; helo=mail-gy0-f180.google.com; envelope-from=myUser@theirDomain.com; receiver=451d9b70cf9364d23ff6f9d51d870251569e+ahoy@inbound.postmarkapp.com"}, {:name=>"DKIM-Signature", :value=>"v=1; a=rsa-sha256; c=relaxed/relaxed; d=wildbit.com; s=google; h=mime-version:reply-to:date:message-id:subject:from:to:cc :content-type; bh=cYr/+oQiklaYbBJOQU3CdAnyhCTuvemrU36WT7cPNt0=; b=QsegXXbTbC4CMirl7A3VjDHyXbEsbCUTPL5vEHa7hNkkUTxXOK+dQA0JwgBHq5C+1u iuAJMz+SNBoTqEDqte2ckDvG2SeFR+Edip10p80TFGLp5RucaYvkwJTyuwsA7xd78NKT Q9ou6L1hgy/MbKChnp2kxHOtYNOrrszY3JfQM="}, {:name=>"MIME-Version", :value=>"1.0"}, {:name=>"Message-ID", :value=>"<CAGXpo2WKfxHWZ5UFYCR3H_J9SNMG+5AXUovfEFL6DjWBJSyZaA@mail.gmail.com>"}], :attachments=>[{:name=>"myimage.png", :content=>"[BASE64-ENCODED CONTENT]", :content_type=>"image/png", :content_length=>4096}, {:name=>"mypaper.doc", :content=>"[BASE64-ENCODED CONTENT]", :content_type=>"application/msword", :content_length=>16384}]}
222
+ ```
223
+
224
+ ## Working with bounces
225
+
226
+ Use `#get_bounces` to retrieve a list of bounces (use `:count` and `:offset`
227
+ parameters to control pagination).
228
+
229
+ ``` ruby
230
+ client.get_bounces(count: 1, offset: 0)
231
+ # => [{:id=>654714902, :type=>"Transient", :type_code=>2, :name=>"Message delayed", :message_id=>"1fdf3729-xxxx-4d5c-8a7b-96da7a23268b", :description=>"The server could not temporarily deliver your message (ex: Message is delayed due to network troubles).", :details=>"action: failed\r\n", :email=>"tema@wildbit.org", :bounced_at=>"2013-04-10T01:01:35.0965184-04:00", :dump_available=>true, :inactive=>false, :can_activate=>true, :subject=>"bounce test"}]
232
+ ```
233
+
234
+ Use `#get_bounced_tags` to retrieve a list of tags used for bounced emails.
235
+
236
+ ``` ruby
237
+ client.get_bounced_tags
238
+ # => ["confidential"]
239
+ ```
240
+
241
+ Use `#get_bounce` to get info for a specific bounce using ID:
242
+
243
+ ``` ruby
244
+ client.get_bounce(654714902)
245
+ # => {:id=>654714902, :type=>"Transient", :type_code=>2, :name=>"Message delayed", :message_id=>"1fdf3729-xxxx-xxxx-8a7b-96da7a23268b", :description=>"The server could not temporarily deliver your message (ex: Message is delayed due to network troubles).", :details=>"action: failed\r\n", :email=>"tema@wildbit.com", :bounced_at=>"2013-04-10T01:01:35.0965184-04:00", :dump_available=>true, :inactive=>false, :can_activate=>true, :subject=>"bounce test", :content=>"..."}
246
+ ```
247
+
248
+ Use `#dump_bounce` to get the full bounce body:
249
+
250
+ ``` ruby
251
+ client.dump_bounce(654714902)
252
+ # => {:body=>"Return-Path: <>\r\nReceived: from m1.mtasv.net (74.205.19.136) by sc-ord-mail2.mtasv.net id hcjov61jk5ko for <pm_bounces@pm.mtasv.net>; Wed, 10 Apr 2013 01:00:35 -0400 (envelope-from <>)\r\nDate: Wed, 10 Apr 2013 01:00:48 -0400\r\nFrom: postmaster@m1.mtasv.net\r\n..."}
253
+ ```
38
254
 
39
- ### Plain text message
255
+ You can activate email addresses that were disabled due to a hard bounce by using `#activate_bounce`:
256
+
257
+ ``` ruby
258
+ client.activate_bounce(654714902)
259
+ # => {:id=>654714902, :type=>"Transient", :type_code=>2, :name=>"Message delayed", :message_id=>"1fdf3729-xxxx-xxxx-xxxx-96da7a23268b", :description=>"The server could not temporarily deliver your message (ex: Message is delayed due to network troubles).", :details=>"action: failed\r\n", :email=>"tema@wildbit.com", :bounced_at=>"2013-04-10T01:01:35.0965184-04:00", :dump_available=>true, :inactive=>false, :can_activate=>true, :subject=>"bounce test"}
260
+ ```
261
+
262
+ ## Getting delivery stats
263
+
264
+ Currently delivery stats only include a summary of inactive emails and bounces
265
+ by type.
266
+
267
+ ``` ruby
268
+ stats = client.delivery_stats
269
+ # => {:inactive_mails=>1, :bounces=>[{:name=>"All", :count=>3}, {:type=>"HardBounce", :name=>"Hard bounce", :count=>2}, {:type=>"Transient", :name=>"Message delayed", :count=>1}]}
270
+ ```
271
+
272
+ ## Server Info
273
+
274
+ The gem also allows you to read and update the server info:
275
+
276
+ ``` ruby
277
+ client.server_info
278
+ # => {:name=>"Testing", :color=>"blue", :bounce_hook_url=>"", :inbound_hash=>"c2ffffff74f8643e5f6086c81", :inbound_hook_url=>"", :smtp_api_activated=>true}
279
+ ```
280
+
281
+ For example, you can use `#update_server_info` to set inbound hook URL:
282
+
283
+ ``` ruby
284
+ client.update_server_info inbound_hook_url: 'http://example.org/bounces'
285
+ ```
286
+
287
+ # Using Postmark with the [Mail](http://rubygems.org/gems/mail) library
288
+
289
+ You can use Postmark with the `mail` gem.
290
+
291
+ ``` bash
292
+ gem install mail
293
+ ```
294
+
295
+ Make sure you have a [sender signature](https://postmarkapp.com/signatures) for
296
+ every `From` email address you specify.
297
+
298
+ To send a `Mail::Message` via Postmark you’ll need to specify `Mail::Postmark` as
299
+ a delivery method for the message:
300
+
301
+ ``` ruby
302
+ message = Mail.new do
303
+ # ...
304
+ delivery_method Mail::Postmark, api_key: 'your-postmark-api-key', secure: true
305
+ end
306
+ ```
307
+
308
+ Delivery method accepts all options supported by `Postmark::ApiClient`
309
+ documented above. A new instance of `Postmark::ApiClient` is created every time
310
+ you deliver a message to preserve thread safety.
311
+
312
+ ## Plain text message
40
313
 
41
314
  ``` ruby
42
315
  require 'rubygems'
@@ -58,7 +331,7 @@ message.deliver
58
331
  # => #<Mail::Message:70355890541720, Multipart: false, Headers: <From: sheldon@bigbangtheory.com>, <To: leonard@bigbangtheory.com>, <Message-ID: e439fec0-4c89-475b-b3fc-eb446249a051>, <Subject: Re: Come on, Sheldon. It will be fun.>>
59
332
  ```
60
333
 
61
- ### HTML message
334
+ ## HTML message
62
335
 
63
336
  ``` ruby
64
337
  require 'rubygems'
@@ -82,7 +355,7 @@ message.deliver
82
355
  # => #<Mail::Message:70355902117460, Multipart: false, Headers: <From: sheldon@bigbangtheory.com>, <To: leonard@bigbangtheory.com>, <Message-ID: 3a9370a2-6c24-4304-a03c-320a54cc59f7>, <Subject: Re: What, to you, is a large crowd?>, <Content-Type: text/html; charset=UTF-8>>
83
356
  ```
84
357
 
85
- ### Message with attachments
358
+ ## Message with attachments
86
359
 
87
360
  ``` ruby
88
361
  message = Mail.new do
@@ -98,12 +371,12 @@ end
98
371
  message.attachments['sheldon.jpeg'] = File.read('2.jpeg')
99
372
 
100
373
  message.deliver
101
- # => #<Mail::Message:70185826686240, Multipart: true, Headers: <From: leonard@bigbangtheory.com>, <To: sheldon@bigbangtheory.com>, <Message-ID: ba644cc1-b5b1-4bcb-aaf8-2f290b5aad80>, <Subject: Have you seen these pictures of yours?>, <Content-Type: multipart/mixed; boundary=--==_mimepart_5121f9f1ec653_12c53fd569035ad817726>>
374
+ # => #<Mail::Message:70185826686240, Multipart: true, Headers: <From: leonard@bigbangtheory.com>, <To: sheldon@bigbangtheory.com>, <Message-ID: ba644cc1-b5b1-4bcb-aaf8-2f290b5aad80>, <Subject: Have you seen these pictures of yours?>, <Content-Type: multipart/mixed; boundary=--==_mimepart_5121f9f1ec653_12c53fd569035ad817726>>
102
375
  ```
103
376
 
104
- ### Multipart message
377
+ ## Multipart message
105
378
 
106
- You can send multipart messages containing both text and HTML using Postmark gem.
379
+ You can send multipart messages containing both text and HTML using the Postmark gem.
107
380
 
108
381
  ``` ruby
109
382
  require 'rubygems'
@@ -135,7 +408,7 @@ message.deliver
135
408
  # => #<Mail::Message:70355901588620, Multipart: true, Headers: <From: sheldon@bigbangtheory.com>, <To: leonard@bigbangtheory.com>, <Message-ID: cadba131-f6d6-4cfc-9892-16ee738ba54c>, <Subject: Re: Anything Can Happen Thursday>, <Content-Type: multipart/alternative; boundary=--==_mimepart_50ef7a6234a69_a4c73ffd01035adc207b8>>
136
409
  ```
137
410
 
138
- ### Tagged message
411
+ ## Tagged message
139
412
 
140
413
  Postmark also lets you tag your messages.
141
414
 
@@ -152,85 +425,85 @@ message = Mail.new do
152
425
  body 'I couldn\'t sleep knowing that just outside my bedroom is ' \
153
426
  'our living room and just outside our living room is that ' \
154
427
  'hallway and immediately adjacent to that hallway is this!'
428
+ tag 'confidential'
155
429
 
156
430
  delivery_method Mail::Postmark, :api_key => 'your-postmark-api-key'
157
431
  end
158
432
 
159
- message.tag = 'confidential'
160
-
161
433
  message.deliver
162
434
  # => #<Mail::Message:70168327829580, Multipart: false, Headers: <From: sheldon@bigbangtheory.com>, <To: penny@bigbangtheory.com>, <Message-ID: af2570fd-3481-4b45-8b27-a249806d891a>, <Subject: Re: You cleaned my apartment???>, <TAG: confidential>>
163
435
  ```
164
436
 
165
- ### Accessing Postmark Message-ID
437
+ ## Sending in batches
166
438
 
167
- You might want to save identifiers of messages you send. Postmark provides you
168
- with unique Message-ID, which you can
169
- [use to retrieve bounces](http://blog.postmarkapp.com/post/24970994681/using-messageid-to-retrieve-bounces)
170
- later. This example shows you how to access Message-ID of a sent email message.
439
+ You can also send `Mail::Message` objects in batches. Create an instance of
440
+ `Postmark::ApiClient` as described in "Communicating with the API" section.
171
441
 
172
442
  ``` ruby
173
- message = Mail.new
174
- # ...
175
- message.deliver
443
+ messages = []
176
444
 
177
- message['Message-ID']
178
- # => cadba131-f6d6-4cfc-9892-16ee738ba54c
179
- message.message_id
180
- # => "cadba131-f6d6-4cfc-9892-16ee738ba54c"
181
- ```
445
+ messages << Mail.new do
446
+ from 'sheldon@bigbangtheory.com'
447
+ to 'Leonard Hofstadter <leonard@bigbangtheory.com>'
448
+ subject 'Re: Come on, Sheldon. It will be fun.'
449
+ body 'That\'s what you said about the Green Lantern movie. You' \
450
+ 'were 114 minutes of wrong.'
451
+ end
182
452
 
183
- ## Using with [TMail](http://rubygems.org/gems/tmail) library
453
+ messages << Mail.new do
454
+ from 'sheldon@bigbangtheory.com'
455
+ to 'Penny <penny@bigbangtheory.com>'
456
+ subject 'Re: You cleaned my apartment???'
457
+ body 'I couldn\'t sleep knowing that just outside my bedroom is ' \
458
+ 'our living room and just outside our living room is that ' \
459
+ 'hallway and immediately adjacent to that hallway is this!'
460
+ tag 'confidential'
461
+ end
184
462
 
185
- Postmark gem also supports `tmail` library, which can be used by Ruby 1.8.7
186
- users working on legacy projects. Please note that TMail is not supported since
187
- 2010, so please consider using new ruby [mail](http://rubygems.org/gems/mail)
188
- library for all your new projects.
463
+ client.deliver_messages(messages)
464
+ # => [{:to=>"leonard@bigbangtheory.com", :submitted_at=>"2013-05-10T01:59:29.830486-04:00", :message_id=>"8ad0e8b0-xxxx-xxxx-951d-223c581bb467", :error_code=>0, :message=>"OK"}, {:to=>"penny@bigbangtheory.com", :submitted_at=>"2013-05-10T01:59:29.830486-04:00", :message_id=>"33c6240c-xxxx-xxxx-b0df-40bdfcf4e0f7", :error_code=>0, :message=>"OK"}]
465
+ ```
189
466
 
190
- Make sure you have a [sender signature](https://postmarkapp.com/signatures) for
191
- every From email you specify. From can also accept array of addresses.
467
+ After delivering a batch you can check on each message’s delivery status:
192
468
 
193
469
  ``` ruby
194
- require 'rubygems'
195
- require 'postmark'
196
- require 'tmail'
197
- require 'json'
470
+ messages.first.delivered?
471
+ # => true
198
472
 
199
- Postmark.api_key = 'your-postmark-api-key'
200
-
201
- message = TMail::Mail.new
202
- message.from = "leonard@bigbangtheory.com"
203
- message.to = "Sheldon Cooper <sheldon@bigbangtheory.com>"
204
- message.subject = "Hi Sheldon!"
205
- message.content_type = "text/html"
206
- message.body = "Hello my friend!"
473
+ messages.all?(&:delivered)
474
+ # => true
475
+ ```
207
476
 
208
- # You can set customer headers if you like:
209
- message["CUSTOM-HEADER"] = "my custom header value"
477
+ Or even get a related Postmark response:
210
478
 
211
- # Added a tag:
212
- message.tag = "my-tracking-tag"
479
+ ``` ruby
480
+ messages.first.postmark_response
481
+ # => {"To"=>"leonard@bigbangtheory.com", "SubmittedAt"=>"2013-05-10T01:59:29.830486-04:00", "MessageID"=>"8ad0e8b0-xxxx-xxxx-951d-223c581bb467", "ErrorCode"=>0, "Message"=>"OK"}
482
+ ```
213
483
 
214
- # Add attachments:
215
- message.postmark_attachments = [File.open("/path"), File.open("/path")]
484
+ ## Accessing Postmark Message-ID
216
485
 
217
- # Add attachments with content generated on the fly:
218
- message.postmark_attachments = [{
219
- "Name" => "September 2011.pdf",
220
- "Content" => [pdf_content].pack("m"),
221
- "ContentType" => "application/pdf"
222
- }]
486
+ You might want to save identifiers of messages you send. Postmark provides you
487
+ with a unique Message-ID, which you can
488
+ [use to retrieve bounces](http://blog.postmarkapp.com/post/24970994681/using-messageid-to-retrieve-bounces)
489
+ later. This example shows you how to access the Message-ID of a sent email message.
223
490
 
224
- # Or specify a reply-to address (can also be an array of addresses):
225
- message.reply_to = "penny@bigbangtheory.com"
491
+ ``` ruby
492
+ message = Mail.new
493
+ # ...
494
+ message.deliver
226
495
 
227
- Postmark.send_through_postmark(message)
496
+ message['Message-ID']
497
+ # => cadba131-f6d6-4cfc-9892-16ee738ba54c
498
+ message.message_id
499
+ # => "cadba131-f6d6-4cfc-9892-16ee738ba54c"
228
500
  ```
229
501
 
230
- ## Exploring Other API Features
502
+ # Exploring Other Gem Features
231
503
 
232
- You can retrieve various information about your server state using the [Public
233
- bounces API](http://developer.postmarkapp.com/bounces).
504
+ To provide an interface similar to ActiveRecord for bounces, the Postmark gem adds
505
+ `Postmark::Bounce` class. This class uses the shared `Postmark::ApiClient` instance
506
+ configured through the Postmark module.
234
507
 
235
508
  ``` ruby
236
509
  require 'rubygems'
@@ -241,10 +514,6 @@ require 'json'
241
514
  Postmark.response_parser_class = :Json
242
515
  Postmark.api_key = 'your-postmark-api-key'
243
516
 
244
- # Delivery stats
245
- Postmark.delivery_stats
246
- # => {"InactiveMails"=>1, "Bounces"=>[{"Name"=>"All", "Count"=>1}, {"Type"=>"HardBounce", "Name"=>"Hard bounce", "Count"=>1}]}
247
-
248
517
  # Get bounces information: (array of bounce objects)
249
518
  Postmark::Bounce.all
250
519
  # => [#<Postmark::Bounce:0x007ff09c04ae18 @id=580516117, @email="sheldon@bigbangtheory.com", @bounced_at=2012-10-21 00:01:56 +0800, @type="HardBounce", @name=nil, @details="smtp;550 5.1.1 The email account that you tried to reach does not exist. Please try double-checking the recipient's email address for typos or unnecessary spaces. Learn more at http://support.google.com/mail/bin/answer.py?answer=6596 c13si5382730vcw.23", @tag=nil, @dump_available=false, @inactive=true, @can_activate=true, @message_id="876d40fe-ab2a-4925-9d6f-8d5e4f4926f5", @subject="Re: What, to you, is a large crowd?">]
@@ -260,24 +529,15 @@ bounce.activate # reactivate hard bounce
260
529
  # => #<Postmark::Bounce:0x007ff09c04ae18 @id=580516117, @email="sheldon@bigbangtheory.com", @bounced_at=2012-10-21 00:01:56 +0800, @type="HardBounce", @name=nil, @details="smtp;550 5.1.1 The email account that you tried to reach does not exist. Please try double-checking the recipient's email address for typos or unnecessary spaces. Learn more at http://support.google.com/mail/bin/answer.py?answer=6596 c13si5382730vcw.23", @tag=nil, @dump_available=false, @inactive=true, @can_activate=true, @message_id="876d40fe-ab2a-4925-9d6f-8d5e4f4926f5", @subject="Re: What, to you, is a large crowd?">
261
530
  ```
262
531
 
263
- ## Security
264
-
265
- To use SSL encryption when sending email configure the library as follows:
266
-
267
- ``` ruby
268
- Postmark.secure = true
269
- ```
270
-
271
532
  ## Requirements
272
533
 
273
- The gem relies on Mail or TMail for building the message. You will also need
274
- postmark account, server and sender signature set up to use it.
275
- If you plan using it in a rails project, check out the
534
+ You will need a Postmark account, server and sender signature set up to use it.
535
+ If you plan using it in a Rails project, check out the
276
536
  [postmark-rails](https://github.com/wildbit/postmark-rails/) gem, which
277
537
  is meant to integrate with ActionMailer.
278
538
 
279
539
  The plugin will try to use ActiveSupport Json if it is already included. If not,
280
- it will attempt using the built-in ruby Json library.
540
+ it will attempt using the built-in Ruby Json library.
281
541
 
282
542
  You can also explicitly specify which one to be used, using
283
543