postmark 1.5.0 → 1.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.rdoc +4 -0
- data/README.md +20 -0
- data/VERSION +1 -1
- data/lib/postmark/api_client.rb +57 -1
- data/lib/postmark/version.rb +1 -1
- data/spec/unit/postmark/api_client_spec.rb +256 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17d7c0c5ea350fd8902efaa8e8334dff894fe215
|
4
|
+
data.tar.gz: 17f7871d1544d69b7cf16d75c4ba260048de182c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38df57ae61ce36c80870832444d017083e1bff043901823eb675384ae25df1366f420170abf41059a7601d7a6a2c7e26866a15abf8c5b98fa7fa30b7d8cbeeb8
|
7
|
+
data.tar.gz: 4dcacb79aec065cf65445da357f0b3e275911da17881291124dacd70b0bccacb1a3d69b4779f34f010692b7667710a0e0b6c8214a00af557b65d86746fc0a499
|
data/CHANGELOG.rdoc
CHANGED
data/README.md
CHANGED
@@ -160,6 +160,22 @@ client.deliver(from: 'sheldon@bigbangtheory.com',
|
|
160
160
|
# => {: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"}
|
161
161
|
```
|
162
162
|
|
163
|
+
## Sending a templated email
|
164
|
+
|
165
|
+
If you have a [template created](https://github.com/wildbit/postmark-gem/wiki/The-Templates-API-support) in Postmark you can send an email using that template.
|
166
|
+
|
167
|
+
``` ruby
|
168
|
+
client.deliver_with_template(from: 'sheldon@bigbangtheory.com',
|
169
|
+
to: 'Penny <penny@bigbangtheory.com>',
|
170
|
+
template_id: 123,
|
171
|
+
template_model: {
|
172
|
+
name: 'Penny',
|
173
|
+
message: 'Bazinga!'
|
174
|
+
})
|
175
|
+
|
176
|
+
# => {: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"}
|
177
|
+
```
|
178
|
+
|
163
179
|
## Sending in batches
|
164
180
|
|
165
181
|
While Postmark is focused on transactional email, we understand that developers
|
@@ -544,6 +560,10 @@ Postmark allows you to automatically scale your sending infrastructure with the
|
|
544
560
|
|
545
561
|
If you ever need to access your messages or their metadata (i.e. open tracking info), [the Messages API](https://github.com/wildbit/postmark-gem/wiki/The-Messages-API-support) is a great place to start.
|
546
562
|
|
563
|
+
## The Templates API Support
|
564
|
+
|
565
|
+
[The Templates API](https://github.com/wildbit/postmark-gem/wiki/The-Templates-API-support) can be used to fully manage your templates.
|
566
|
+
|
547
567
|
## ActiveModel-like Interface For Bounces
|
548
568
|
|
549
569
|
To provide an interface similar to ActiveModel for bounces, the Postmark gem adds
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.6.0
|
data/lib/postmark/api_client.rb
CHANGED
@@ -165,6 +165,62 @@ module Postmark
|
|
165
165
|
format_response http_client.put("server", serialize(data))
|
166
166
|
end
|
167
167
|
|
168
|
+
def get_templates(options = {})
|
169
|
+
load_batch('templates', 'Templates', options)
|
170
|
+
end
|
171
|
+
|
172
|
+
def templates(options = {})
|
173
|
+
find_each('templates', 'Templates', options)
|
174
|
+
end
|
175
|
+
|
176
|
+
def get_template(id)
|
177
|
+
format_response http_client.get("templates/#{id}")
|
178
|
+
end
|
179
|
+
|
180
|
+
def create_template(attributes = {})
|
181
|
+
data = serialize(HashHelper.to_postmark(attributes))
|
182
|
+
|
183
|
+
format_response http_client.post('templates', data)
|
184
|
+
end
|
185
|
+
|
186
|
+
def update_template(id, attributes = {})
|
187
|
+
data = serialize(HashHelper.to_postmark(attributes))
|
188
|
+
|
189
|
+
format_response http_client.put("templates/#{id}", data)
|
190
|
+
end
|
191
|
+
|
192
|
+
def delete_template(id)
|
193
|
+
format_response http_client.delete("templates/#{id}")
|
194
|
+
end
|
195
|
+
|
196
|
+
def validate_template(attributes = {})
|
197
|
+
data = serialize(HashHelper.to_postmark(attributes))
|
198
|
+
response = format_response(http_client.post('templates/validate', data))
|
199
|
+
|
200
|
+
response.each do |k, v|
|
201
|
+
next unless v.is_a?(Hash) && k != :suggested_template_model
|
202
|
+
|
203
|
+
response[k] = HashHelper.to_ruby(v)
|
204
|
+
|
205
|
+
if response[k].has_key?(:validation_errors)
|
206
|
+
ruby_hashes = response[k][:validation_errors].map do |err|
|
207
|
+
HashHelper.to_ruby(err)
|
208
|
+
end
|
209
|
+
response[k][:validation_errors] = ruby_hashes
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
response
|
214
|
+
end
|
215
|
+
|
216
|
+
def deliver_with_template(attributes = {})
|
217
|
+
data = serialize(MessageHelper.to_postmark(attributes))
|
218
|
+
|
219
|
+
with_retries do
|
220
|
+
format_response http_client.post('email/withTemplate', data)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
168
224
|
protected
|
169
225
|
|
170
226
|
def in_batches(messages)
|
@@ -195,4 +251,4 @@ module Postmark
|
|
195
251
|
end
|
196
252
|
|
197
253
|
end
|
198
|
-
end
|
254
|
+
end
|
data/lib/postmark/version.rb
CHANGED
@@ -572,4 +572,259 @@ describe Postmark::ApiClient do
|
|
572
572
|
end
|
573
573
|
end
|
574
574
|
|
575
|
-
|
575
|
+
describe '#get_templates' do
|
576
|
+
let(:http_client) { subject.http_client }
|
577
|
+
let(:response) do
|
578
|
+
{
|
579
|
+
'TotalCount' => 31,
|
580
|
+
'Templates' => [
|
581
|
+
{
|
582
|
+
'Active' => true,
|
583
|
+
'TemplateId' => 123,
|
584
|
+
'Name' => 'ABC'
|
585
|
+
},
|
586
|
+
{
|
587
|
+
'Active' => true,
|
588
|
+
'TemplateId' => 456,
|
589
|
+
'Name' => 'DEF'
|
590
|
+
}
|
591
|
+
]
|
592
|
+
}
|
593
|
+
end
|
594
|
+
|
595
|
+
it 'gets templates info and converts it to ruby format' do
|
596
|
+
http_client.should_receive(:get).with('templates', :offset => 0, :count => 2).and_return(response)
|
597
|
+
|
598
|
+
count, templates = subject.get_templates(:count => 2)
|
599
|
+
|
600
|
+
expect(count).to eq(31)
|
601
|
+
expect(templates.first[:template_id]).to eq(123)
|
602
|
+
expect(templates.first[:name]).to eq('ABC')
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
describe '#templates' do
|
607
|
+
it 'returns an Enumerator' do
|
608
|
+
expect(subject.templates).to be_kind_of(Enumerable)
|
609
|
+
end
|
610
|
+
|
611
|
+
it 'requests data at /templates' do
|
612
|
+
allow(subject.http_client).to receive(:get).
|
613
|
+
with('templates', an_instance_of(Hash)).
|
614
|
+
and_return('TotalCount' => 1, 'Templates' => [{}])
|
615
|
+
expect(subject.templates.first(5).count).to eq(1)
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
describe '#get_template' do
|
620
|
+
let(:http_client) { subject.http_client }
|
621
|
+
let(:response) do
|
622
|
+
{
|
623
|
+
'Name' => 'Template Name',
|
624
|
+
'TemplateId' => 123,
|
625
|
+
'Subject' => 'Subject',
|
626
|
+
'HtmlBody' => 'Html',
|
627
|
+
'TextBody' => 'Text',
|
628
|
+
'AssociatedServerId' => 456,
|
629
|
+
'Active' => true
|
630
|
+
}
|
631
|
+
end
|
632
|
+
|
633
|
+
it 'gets single template and converts it to ruby format' do
|
634
|
+
http_client.should_receive(:get).with('templates/123').and_return(response)
|
635
|
+
|
636
|
+
template = subject.get_template('123')
|
637
|
+
|
638
|
+
expect(template[:name]).to eq('Template Name')
|
639
|
+
expect(template[:template_id]).to eq(123)
|
640
|
+
expect(template[:html_body]).to eq('Html')
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
describe '#create_template' do
|
645
|
+
let(:http_client) { subject.http_client }
|
646
|
+
let(:response) do
|
647
|
+
{
|
648
|
+
'TemplateId' => 123,
|
649
|
+
'Name' => 'template name',
|
650
|
+
'Active' => true
|
651
|
+
}
|
652
|
+
end
|
653
|
+
|
654
|
+
it 'performs a POST request to /templates with the given attributes' do
|
655
|
+
expected_json = { 'Name' => 'template name' }.to_json
|
656
|
+
|
657
|
+
http_client.should_receive(:post).with('templates', expected_json).and_return(response)
|
658
|
+
|
659
|
+
template = subject.create_template(:name => 'template name')
|
660
|
+
|
661
|
+
expect(template[:name]).to eq('template name')
|
662
|
+
expect(template[:template_id]).to eq(123)
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
describe '#update_template' do
|
667
|
+
let(:http_client) { subject.http_client }
|
668
|
+
let(:response) do
|
669
|
+
{
|
670
|
+
'TemplateId' => 123,
|
671
|
+
'Name' => 'template name',
|
672
|
+
'Active' => true
|
673
|
+
}
|
674
|
+
end
|
675
|
+
|
676
|
+
it 'performs a PUT request to /templates with the given attributes' do
|
677
|
+
expected_json = { 'Name' => 'template name' }.to_json
|
678
|
+
|
679
|
+
http_client.should_receive(:put).with('templates/123', expected_json).and_return(response)
|
680
|
+
|
681
|
+
template = subject.update_template(123, :name => 'template name')
|
682
|
+
|
683
|
+
expect(template[:name]).to eq('template name')
|
684
|
+
expect(template[:template_id]).to eq(123)
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
describe '#delete_template' do
|
689
|
+
let(:http_client) { subject.http_client }
|
690
|
+
let(:response) do
|
691
|
+
{
|
692
|
+
'ErrorCode' => 0,
|
693
|
+
'Message' => 'Template 123 removed.'
|
694
|
+
}
|
695
|
+
end
|
696
|
+
|
697
|
+
it 'performs a DELETE request to /templates/:id' do
|
698
|
+
http_client.should_receive(:delete).with('templates/123').and_return(response)
|
699
|
+
|
700
|
+
resp = subject.delete_template(123)
|
701
|
+
|
702
|
+
expect(resp[:error_code]).to eq(0)
|
703
|
+
end
|
704
|
+
end
|
705
|
+
|
706
|
+
describe '#validate_template' do
|
707
|
+
let(:http_client) { subject.http_client }
|
708
|
+
|
709
|
+
context 'when template is valid' do
|
710
|
+
let(:response) do
|
711
|
+
{
|
712
|
+
'AllContentIsValid' => true,
|
713
|
+
'HtmlBody' => {
|
714
|
+
'ContentIsValid' => true,
|
715
|
+
'ValidationErrors' => [],
|
716
|
+
'RenderedContent' => '<html><head></head><body>MyName_Value</body></html>'
|
717
|
+
},
|
718
|
+
'TextBody' => {
|
719
|
+
'ContentIsValid' => true,
|
720
|
+
'ValidationErrors' => [],
|
721
|
+
'RenderedContent' => 'MyName_Value'
|
722
|
+
},
|
723
|
+
'Subject' => {
|
724
|
+
'ContentIsValid' => true,
|
725
|
+
'ValidationErrors' => [],
|
726
|
+
'RenderedContent' => 'MyName_Value'
|
727
|
+
},
|
728
|
+
'SuggestedTemplateModel' => {
|
729
|
+
'MyName' => 'MyName_Value'
|
730
|
+
}
|
731
|
+
}
|
732
|
+
end
|
733
|
+
|
734
|
+
it 'performs a POST request and returns unmodified suggested template model' do
|
735
|
+
expected_template_json = {
|
736
|
+
'HtmlBody' => '{{MyName}}',
|
737
|
+
'TextBody' => '{{MyName}}',
|
738
|
+
'Subject' => '{{MyName}}'
|
739
|
+
}.to_json
|
740
|
+
|
741
|
+
http_client.should_receive(:post).with('templates/validate', expected_template_json).and_return(response)
|
742
|
+
|
743
|
+
resp = subject.validate_template(:html_body => '{{MyName}}',
|
744
|
+
:text_body => '{{MyName}}',
|
745
|
+
:subject => '{{MyName}}')
|
746
|
+
|
747
|
+
expect(resp[:all_content_is_valid]).to be_true
|
748
|
+
expect(resp[:html_body][:content_is_valid]).to be_true
|
749
|
+
expect(resp[:html_body][:validation_errors]).to be_empty
|
750
|
+
expect(resp[:suggested_template_model]['MyName']).to eq('MyName_Value')
|
751
|
+
end
|
752
|
+
end
|
753
|
+
|
754
|
+
context 'when template is invalid' do
|
755
|
+
let(:response) do
|
756
|
+
{
|
757
|
+
'AllContentIsValid' => false,
|
758
|
+
'HtmlBody' => {
|
759
|
+
'ContentIsValid' => false,
|
760
|
+
'ValidationErrors' => [
|
761
|
+
{
|
762
|
+
'Message' => 'The \'each\' block being opened requires a model path to be specified in the form \'{#each <name>}\'.',
|
763
|
+
'Line' => 1,
|
764
|
+
'CharacterPosition' => 1
|
765
|
+
}
|
766
|
+
],
|
767
|
+
'RenderedContent' => nil
|
768
|
+
},
|
769
|
+
'TextBody' => {
|
770
|
+
'ContentIsValid' => true,
|
771
|
+
'ValidationErrors' => [],
|
772
|
+
'RenderedContent' => 'MyName_Value'
|
773
|
+
},
|
774
|
+
'Subject' => {
|
775
|
+
'ContentIsValid' => true,
|
776
|
+
'ValidationErrors' => [],
|
777
|
+
'RenderedContent' => 'MyName_Value'
|
778
|
+
},
|
779
|
+
'SuggestedTemplateModel' => nil
|
780
|
+
}
|
781
|
+
end
|
782
|
+
|
783
|
+
it 'performs a POST request and returns validation errors' do
|
784
|
+
expected_template_json = {
|
785
|
+
'HtmlBody' => '{{#each}}',
|
786
|
+
'TextBody' => '{{MyName}}',
|
787
|
+
'Subject' => '{{MyName}}'
|
788
|
+
}.to_json
|
789
|
+
|
790
|
+
http_client.should_receive(:post).with('templates/validate', expected_template_json).and_return(response)
|
791
|
+
|
792
|
+
resp = subject.validate_template(:html_body => '{{#each}}',
|
793
|
+
:text_body => '{{MyName}}',
|
794
|
+
:subject => '{{MyName}}')
|
795
|
+
|
796
|
+
expect(resp[:all_content_is_valid]).to be_false
|
797
|
+
expect(resp[:text_body][:content_is_valid]).to be_true
|
798
|
+
expect(resp[:html_body][:content_is_valid]).to be_false
|
799
|
+
expect(resp[:html_body][:validation_errors].first[:character_position]).to eq(1)
|
800
|
+
expect(resp[:html_body][:validation_errors].first[:message]).to eq('The \'each\' block being opened requires a model path to be specified in the form \'{#each <name>}\'.')
|
801
|
+
end
|
802
|
+
end
|
803
|
+
end
|
804
|
+
|
805
|
+
describe "#deliver_with_template" do
|
806
|
+
let(:email) { Postmark::MessageHelper.to_postmark(message_hash) }
|
807
|
+
let(:email_json) { Postmark::Json.encode(email) }
|
808
|
+
let(:http_client) { subject.http_client }
|
809
|
+
let(:response) { {"MessageID" => 42} }
|
810
|
+
|
811
|
+
it 'converts message hash to Postmark format and posts it to /email/withTemplate' do
|
812
|
+
http_client.should_receive(:post).with('email/withTemplate', email_json) { response }
|
813
|
+
subject.deliver_with_template(message_hash)
|
814
|
+
end
|
815
|
+
|
816
|
+
it 'retries 3 times' do
|
817
|
+
2.times do
|
818
|
+
http_client.should_receive(:post).and_raise(Postmark::InternalServerError)
|
819
|
+
end
|
820
|
+
http_client.should_receive(:post) { response }
|
821
|
+
expect { subject.deliver_with_template(message_hash) }.not_to raise_error
|
822
|
+
end
|
823
|
+
|
824
|
+
it 'converts response to ruby format' do
|
825
|
+
http_client.should_receive(:post).with('email/withTemplate', email_json) { response }
|
826
|
+
r = subject.deliver_with_template(message_hash)
|
827
|
+
r.should have_key(:message_id)
|
828
|
+
end
|
829
|
+
end
|
830
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: postmark
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Petyo Ivanov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-08-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
@@ -141,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
141
|
version: 1.3.7
|
142
142
|
requirements: []
|
143
143
|
rubyforge_project:
|
144
|
-
rubygems_version: 2.
|
144
|
+
rubygems_version: 2.4.5
|
145
145
|
signing_key:
|
146
146
|
specification_version: 4
|
147
147
|
summary: Official Postmark API wrapper.
|