mailgun-ruby 1.2.13 → 1.2.14
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.md +22 -2
- data/README.md +1 -1
- data/docs/Domains.md +1 -1
- data/docs/Events.md +1 -1
- data/docs/MessageBuilder.md +1 -1
- data/docs/Messages.md +1 -1
- data/docs/OptInHandler.md +1 -1
- data/docs/Snippets.md +1 -1
- data/docs/Webhooks.md +1 -1
- data/lib/mailgun/client.rb +12 -2
- data/lib/mailgun/domains/domains.rb +229 -1
- data/lib/mailgun/messages/message_builder.rb +8 -0
- data/lib/mailgun/tags/tags.rb +120 -0
- data/lib/mailgun/version.rb +1 -1
- data/lib/mailgun/webhooks/webhooks.rb +20 -4
- data/lib/mailgun.rb +1 -0
- data/lib/railgun/mailer.rb +29 -0
- data/spec/integration/domains_spec.rb +244 -0
- data/spec/integration/events_spec.rb +1 -1
- data/spec/integration/mailer_spec.rb +2 -8
- data/spec/integration/tags.rb +139 -0
- data/spec/integration/webhook_spec.rb +10 -10
- data/spec/unit/messages/message_builder_spec.rb +11 -0
- data/spec/unit/railgun/content_type_spec.rb +17 -0
- data/vcr_cassettes/domains.yml +1068 -1
- data/vcr_cassettes/tags.yml +417 -0
- data/vcr_cassettes/webhooks.yml +156 -186
- metadata +6 -2
@@ -44,4 +44,248 @@ describe 'For the domains endpoint', vcr: vcr_opts do
|
|
44
44
|
expect(result['domain']["web_scheme"]).to eq('https')
|
45
45
|
expect(result['domain']["wildcard"]).to eq(true)
|
46
46
|
end
|
47
|
+
|
48
|
+
describe '#create_smtp_credentials' do
|
49
|
+
it 'creates smtp credentials for domain' do
|
50
|
+
result = @mg_obj.create_smtp_credentials(
|
51
|
+
@domain,
|
52
|
+
{
|
53
|
+
login: 'test_login',
|
54
|
+
password: 'test_password'
|
55
|
+
}
|
56
|
+
)
|
57
|
+
|
58
|
+
expect(result['message']).to eq("Created 1 credentials pair(s)")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#update_smtp_credentials' do
|
63
|
+
it 'updates smtp credentials for domain' do
|
64
|
+
result = @mg_obj.update_smtp_credentials(
|
65
|
+
@domain,
|
66
|
+
'test_login',
|
67
|
+
{
|
68
|
+
password: 'test_password2'
|
69
|
+
}
|
70
|
+
)
|
71
|
+
|
72
|
+
expect(result['message']).to eq('Password changed')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#delete_smtp_credentials' do
|
77
|
+
it 'deletes smtp credentials for domain' do
|
78
|
+
result = @mg_obj.delete_smtp_credentials(
|
79
|
+
@domain,
|
80
|
+
'test_login'
|
81
|
+
)
|
82
|
+
|
83
|
+
expect(result['message']).to eq('Credentials have been deleted')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '#delete_smtp_credentials' do
|
88
|
+
it 'deletes smtp credentials for domain' do
|
89
|
+
result = @mg_obj.delete_smtp_credentials(
|
90
|
+
@domain,
|
91
|
+
'test_login'
|
92
|
+
)
|
93
|
+
|
94
|
+
expect(result['message']).to eq('Credentials have been deleted')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#get_domain_connection_settings' do
|
99
|
+
it 'returns delivery connection settings for the defined domain' do
|
100
|
+
result = @mg_obj.get_domain_connection_settings(
|
101
|
+
@domain
|
102
|
+
)
|
103
|
+
|
104
|
+
expect(result).to include(
|
105
|
+
'require_tls' => false,
|
106
|
+
'skip_verification' => false
|
107
|
+
)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#update_domain_connection_settings' do
|
112
|
+
it 'updates the specified delivery connection settings' do
|
113
|
+
result = @mg_obj.update_domain_connection_settings(
|
114
|
+
@domain,
|
115
|
+
{
|
116
|
+
require_tls: true,
|
117
|
+
skip_verification: true
|
118
|
+
}
|
119
|
+
)
|
120
|
+
|
121
|
+
expect(result).to include(
|
122
|
+
'require_tls' => true,
|
123
|
+
'skip_verification' => true
|
124
|
+
)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#get_domain_tracking_settings' do
|
129
|
+
it 'returns tracking settings for the defined domain' do
|
130
|
+
result = @mg_obj.get_domain_tracking_settings(
|
131
|
+
@domain
|
132
|
+
)
|
133
|
+
|
134
|
+
expect(result).to include('tracking')
|
135
|
+
expect(result['tracking']['click']['active']).to eq(true)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#update_domain_tracking_open_settings' do
|
140
|
+
it 'updates the specified tracking open settings' do
|
141
|
+
result = @mg_obj.update_domain_tracking_open_settings(
|
142
|
+
@domain,
|
143
|
+
{
|
144
|
+
active: false
|
145
|
+
}
|
146
|
+
)
|
147
|
+
|
148
|
+
expect(result['open']['active']).to eq(false)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe '#update_domain_tracking_click_settings' do
|
153
|
+
it 'updates the specified tracking click settings' do
|
154
|
+
result = @mg_obj.update_domain_tracking_click_settings(
|
155
|
+
@domain,
|
156
|
+
{
|
157
|
+
active: false
|
158
|
+
}
|
159
|
+
)
|
160
|
+
|
161
|
+
expect(result['click']['active']).to eq(false)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#update_domain_tracking_unsubscribe_settings' do
|
166
|
+
it 'updates the specified tracking unsubscribe settings' do
|
167
|
+
result = @mg_obj.update_domain_tracking_unsubscribe_settings(
|
168
|
+
@domain,
|
169
|
+
{
|
170
|
+
active: false
|
171
|
+
}
|
172
|
+
)
|
173
|
+
|
174
|
+
expect(result['unsubscribe']['active']).to eq(false)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe '#update_domain_dkim_authority' do
|
179
|
+
it 'updates the DKIM authority for a domain' do
|
180
|
+
result = @mg_obj.update_domain_dkim_authority(
|
181
|
+
@domain,
|
182
|
+
{
|
183
|
+
active: false
|
184
|
+
}
|
185
|
+
)
|
186
|
+
|
187
|
+
expect(result['message']).to eq('Domain DKIM authority has been changed')
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe '#update_domain_dkim_selector' do
|
192
|
+
it 'updates the DKIM selector for a domain' do
|
193
|
+
result = @mg_obj.update_domain_dkim_selector(
|
194
|
+
@domain,
|
195
|
+
{
|
196
|
+
dkim_selector: 'mailo1'
|
197
|
+
}
|
198
|
+
)
|
199
|
+
|
200
|
+
expect(result['message']).to eq('Domain DKIM authority changed')
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe '#update_domain_web_prefix' do
|
205
|
+
it 'updates the the CNAME used for tracking opens and clicks' do
|
206
|
+
result = @mg_obj.update_domain_web_prefix(
|
207
|
+
@domain,
|
208
|
+
{
|
209
|
+
web_prefix: 'email'
|
210
|
+
}
|
211
|
+
)
|
212
|
+
|
213
|
+
expect(result['message']).to eq('Domain web prefix updated')
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe 'V4' do
|
218
|
+
before do
|
219
|
+
@mg_client = Mailgun::Client.new(APIKEY, APIHOST, 'v4', SSL)
|
220
|
+
@mg_obj = Mailgun::Domains.new(@mg_client)
|
221
|
+
end
|
222
|
+
|
223
|
+
describe '#get_domain_keys' do
|
224
|
+
it 'lists the domain keys for a specified signing domain' do
|
225
|
+
result = @mg_obj.get_domain_keys(
|
226
|
+
@domain
|
227
|
+
)
|
228
|
+
|
229
|
+
expect(result).to include('items')
|
230
|
+
expect(result['items'].first['selector']).to eq('mailo1')
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
describe '#activate_domain_key' do
|
235
|
+
it 'activates a domain key' do
|
236
|
+
result = @mg_obj.activate_domain_key(
|
237
|
+
@domain,
|
238
|
+
'smtp'
|
239
|
+
)
|
240
|
+
|
241
|
+
expect(result['message']).to eq('domain key activated')
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe '#deactivate_domain_key' do
|
246
|
+
it 'deactivates a domain key' do
|
247
|
+
result = @mg_obj.deactivate_domain_key(
|
248
|
+
{
|
249
|
+
signing_domain: 'x509.zeefarmer.com',
|
250
|
+
selector: 'tetetet'
|
251
|
+
}
|
252
|
+
)
|
253
|
+
|
254
|
+
expect(result['message']).to eq('domain key deactivated')
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe '#delete_domain_key' do
|
260
|
+
before do
|
261
|
+
@mg_client = Mailgun::Client.new(APIKEY, APIHOST, 'v1', SSL)
|
262
|
+
@mg_obj = Mailgun::Domains.new(@mg_client)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'deletes a domain key' do
|
266
|
+
result = @mg_obj.delete_domain_key(
|
267
|
+
{
|
268
|
+
signing_domain: @domain,
|
269
|
+
selector: 'test'
|
270
|
+
}
|
271
|
+
)
|
272
|
+
|
273
|
+
expect(result['message']).to eq('success')
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
describe '#get_domain_stats' do
|
278
|
+
it 'returns total stats for a given domain' do
|
279
|
+
result = @mg_obj.get_domain_stats(
|
280
|
+
@domain,
|
281
|
+
{
|
282
|
+
event: 'clicked',
|
283
|
+
start: 'Sun, 23 Dec 2023 01:23:45 JST',
|
284
|
+
duration: '24h'
|
285
|
+
}
|
286
|
+
)
|
287
|
+
|
288
|
+
expect(result).to include('stats')
|
289
|
+
end
|
290
|
+
end
|
47
291
|
end
|
@@ -53,15 +53,9 @@ describe 'Invalid domain', vcr: vcr_opts do
|
|
53
53
|
domain: domain
|
54
54
|
}
|
55
55
|
end
|
56
|
-
let(:mail) { UnitTestMailer.plain_message(
|
56
|
+
let(:mail) { UnitTestMailer.plain_message('sally@not-our-doma.in', "bob@#{domain}", 'subject', {}) }
|
57
57
|
|
58
58
|
it 'raises expected error' do
|
59
|
-
|
60
|
-
Railgun::Mailer.new(config).deliver!(mail)
|
61
|
-
rescue Mailgun::CommunicationError => err
|
62
|
-
expect(err.message).to eq('401 Unauthorized: Forbidden - Invalid Domain or API key')
|
63
|
-
else
|
64
|
-
fail
|
65
|
-
|
59
|
+
expect { Railgun::Mailer.new(config).deliver!(mail) }.to raise_error Mailgun::CommunicationError, /Forbidden/
|
66
60
|
end
|
67
61
|
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mailgun'
|
3
|
+
|
4
|
+
vcr_opts = { :cassette_name => "tags" }
|
5
|
+
|
6
|
+
describe 'For the tags endpoints', vcr: vcr_opts do
|
7
|
+
let(:tag_name) { 'abtest-option-a' }
|
8
|
+
let(:domain) { "integration-test.domain.invalid" }
|
9
|
+
|
10
|
+
before(:all) do
|
11
|
+
@mg_client = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
|
12
|
+
@tags = Mailgun::Tags.new(@mg_client)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#get_tags' do
|
16
|
+
it 'returs tags info' do
|
17
|
+
result = @tags.get_tags(domain)
|
18
|
+
|
19
|
+
expect(result.first['tag']).to eq('You can track mails as tag-units!')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#get_tag' do
|
24
|
+
it "return the tag's info" do
|
25
|
+
result = @tags.get_tag(domain, tag_name)
|
26
|
+
|
27
|
+
expect(result['tag']).to eq(tag_name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#update' do
|
32
|
+
it "returns true" do
|
33
|
+
result = @tags.update(
|
34
|
+
domain,
|
35
|
+
tag_name,
|
36
|
+
{ description: 'new description 2' }
|
37
|
+
)
|
38
|
+
|
39
|
+
expect(result).to eq(true)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#get_tag_stats' do
|
44
|
+
it "returns tag stats info" do
|
45
|
+
result = @tags.get_tag_stats(
|
46
|
+
domain,
|
47
|
+
tag_name,
|
48
|
+
{
|
49
|
+
event: 'accepted',
|
50
|
+
start: 'Tue, 23 Jan 2024 11:23:45 EST',
|
51
|
+
resolution: 'day'
|
52
|
+
}
|
53
|
+
)
|
54
|
+
|
55
|
+
expect(result).to include('stats')
|
56
|
+
expect(result['stats'].first['accepted']).to include(
|
57
|
+
{
|
58
|
+
'incoming' => 0,
|
59
|
+
'outgoing' => 0,
|
60
|
+
'total' => 0
|
61
|
+
}
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#get_countries_aggregated_stats' do
|
67
|
+
it "returns countries of origin for a given domain" do
|
68
|
+
result = @tags.get_countries_aggregated_stats(
|
69
|
+
domain,
|
70
|
+
tag_name
|
71
|
+
)
|
72
|
+
|
73
|
+
expect(result).to include('country')
|
74
|
+
expect(result['country']['ad']).to include(
|
75
|
+
{
|
76
|
+
'clicked' => 0,
|
77
|
+
'complained' => 0,
|
78
|
+
'opened' => 0,
|
79
|
+
'unique_clicked' => 0,
|
80
|
+
'unique_opened' => 0,
|
81
|
+
'unsubscribed' => 0
|
82
|
+
}
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '#get_providers_aggregated_stats' do
|
88
|
+
it "returns email providers for a given domain" do
|
89
|
+
result = @tags.get_providers_aggregated_stats(
|
90
|
+
domain,
|
91
|
+
tag_name
|
92
|
+
)
|
93
|
+
|
94
|
+
expect(result).to include('provider')
|
95
|
+
expect(result['provider']['aol.com']).to include(
|
96
|
+
{
|
97
|
+
'clicked' => 0,
|
98
|
+
'complained' => 0,
|
99
|
+
'opened' => 0,
|
100
|
+
'unique_clicked' => 0,
|
101
|
+
'unique_opened' => 0,
|
102
|
+
'unsubscribed' => 0
|
103
|
+
}
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '#get_devices_aggregated_stats' do
|
109
|
+
it "returns devices for a given domain" do
|
110
|
+
result = @tags.get_devices_aggregated_stats(
|
111
|
+
domain,
|
112
|
+
tag_name
|
113
|
+
)
|
114
|
+
|
115
|
+
expect(result).to include('device')
|
116
|
+
expect(result['device']['desktop']).to include(
|
117
|
+
{
|
118
|
+
'clicked' => 0,
|
119
|
+
'complained' => 0,
|
120
|
+
'opened' => 28,
|
121
|
+
'unique_clicked' => 0,
|
122
|
+
'unique_opened' => 24,
|
123
|
+
'unsubscribed' => 0
|
124
|
+
}
|
125
|
+
)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe '#remove' do
|
130
|
+
it "returns true" do
|
131
|
+
result = @tags.remove(
|
132
|
+
domain,
|
133
|
+
tag_name
|
134
|
+
)
|
135
|
+
|
136
|
+
expect(result).to eq(true)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -7,48 +7,48 @@ describe 'For the webhooks endpoint', order: :defined, vcr: vcr_opts do
|
|
7
7
|
before(:all) do
|
8
8
|
@mg_obj = Mailgun::Client.new(APIKEY, APIHOST, APIVERSION, SSL)
|
9
9
|
@domain = TESTDOMAIN
|
10
|
-
@testhook = '
|
11
|
-
@testhookup = '
|
10
|
+
@testhook = 'accepted'
|
11
|
+
@testhookup = 'accepted'
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'creates a webhook' do
|
15
|
-
result = @mg_obj.post("domains/#{@domain}/webhooks", { id:
|
15
|
+
result = @mg_obj.post("domains/#{@domain}/webhooks", { id: @testhook,
|
16
16
|
url: "http://example.com/mailgun/events/#{@testhook}" } )
|
17
17
|
|
18
18
|
result.to_h!
|
19
19
|
expect(result.body["message"]).to eq("Webhook has been created")
|
20
|
-
expect(result.body["webhook"]["
|
20
|
+
expect(result.body["webhook"]["urls"]).to include("http://example.com/mailgun/events/#{@testhook}")
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'gets a webhook.' do
|
24
24
|
result = @mg_obj.get("domains/#{@domain}/webhooks/#{@testhook}")
|
25
25
|
|
26
26
|
result.to_h!
|
27
|
-
expect(result.body["webhook"]["
|
27
|
+
expect(result.body["webhook"]["urls"]).to include("http://example.com/mailgun/events/#{@testhook}")
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'gets a list of all webhooks.' do
|
31
31
|
result = @mg_obj.get("domains/#{@domain}/webhooks")
|
32
32
|
|
33
33
|
result.to_h!
|
34
|
-
expect(result.body["webhooks"]["
|
34
|
+
expect(result.body["webhooks"]["accepted"]["urls"]).to include("http://example.com/mailgun/events/#{@testhook}")
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'updates a webhook.' do
|
38
|
-
result = @mg_obj.put("domains/#{@domain}/webhooks
|
38
|
+
result = @mg_obj.put("domains/#{@domain}/webhooks/#{@testhook}", {:id => @testhook,
|
39
39
|
:url => "http://example.com/mailgun/events/#{@testhookup}"})
|
40
40
|
|
41
41
|
result.to_h!
|
42
42
|
expect(result.body["message"]).to eq("Webhook has been updated")
|
43
|
-
expect(result.body["webhook"]["
|
43
|
+
expect(result.body["webhook"]["urls"]).to include("http://example.com/mailgun/events/#{@testhookup}")
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'removes a webhook' do
|
47
|
-
result = @mg_obj.delete("domains/#{@domain}/webhooks
|
47
|
+
result = @mg_obj.delete("domains/#{@domain}/webhooks/#{@testhook}")
|
48
48
|
|
49
49
|
result.to_h!
|
50
50
|
expect(result.body['message']).to eq("Webhook has been deleted")
|
51
|
-
expect(result.body['webhook']['
|
51
|
+
expect(result.body['webhook']['urls']).to include("http://example.com/mailgun/events/#{@testhookup}")
|
52
52
|
end
|
53
53
|
|
54
54
|
end
|
@@ -186,6 +186,17 @@ describe 'The method body_text' do
|
|
186
186
|
end
|
187
187
|
end
|
188
188
|
|
189
|
+
describe 'The method amp_html' do
|
190
|
+
it 'sets amp-html to a string, not an array' do
|
191
|
+
the_text = 'Don\'t mess with Texas!'
|
192
|
+
@mb_obj = Mailgun::MessageBuilder.new
|
193
|
+
@mb_obj.amp_html(the_text)
|
194
|
+
expect(@mb_obj.message['amp-html']).to be_a(String)
|
195
|
+
expect(@mb_obj.message['amp-html']).to eq(the_text)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
|
189
200
|
describe 'The method set_from_address' do
|
190
201
|
it 'warns of set_from_address deprecation' do
|
191
202
|
@mb_obj = Mailgun::MessageBuilder.new
|
@@ -26,6 +26,17 @@ describe 'extract_body' do
|
|
26
26
|
}
|
27
27
|
let(:html_content) { '<h3> [TEST] </h3> <br/> Hello, world!' }
|
28
28
|
|
29
|
+
let(:amp_mail_option) {
|
30
|
+
{
|
31
|
+
from: 'bob@example.com',
|
32
|
+
to: 'sally@example.com',
|
33
|
+
subject: 'RAILGUN TEST SAMPLE',
|
34
|
+
body: amp_content,
|
35
|
+
content_type: 'text/x-amp-html',
|
36
|
+
}
|
37
|
+
}
|
38
|
+
let(:amp_content) { '<h3> [TEST] </h3> <br/> Hello from AMP!' }
|
39
|
+
|
29
40
|
context 'with <Content-Type: text/plain>' do
|
30
41
|
let(:sample_mail) { Mail.new(text_mail_option) }
|
31
42
|
|
@@ -53,10 +64,12 @@ describe 'extract_body' do
|
|
53
64
|
context 'with <Content-Type: multipart/alternative>' do
|
54
65
|
let(:text_mail) { Mail.new(text_mail_option) }
|
55
66
|
let(:html_mail) { Mail.new(html_mail_option) }
|
67
|
+
let(:amp_mail) { Mail.new(amp_mail_option) }
|
56
68
|
|
57
69
|
before do
|
58
70
|
@sample_mail = Mail::Part.new(content_type: "multipart/alternative")
|
59
71
|
@sample_mail.add_part text_mail
|
72
|
+
@sample_mail.add_part amp_mail
|
60
73
|
@sample_mail.add_part html_mail
|
61
74
|
end
|
62
75
|
|
@@ -67,5 +80,9 @@ describe 'extract_body' do
|
|
67
80
|
it 'should return body html' do
|
68
81
|
expect(Railgun.extract_body_html(@sample_mail)).to eq(html_content)
|
69
82
|
end
|
83
|
+
|
84
|
+
it 'should return AMP html' do
|
85
|
+
expect(Railgun.extract_amp_html(@sample_mail)).to eq(amp_content)
|
86
|
+
end
|
70
87
|
end
|
71
88
|
end
|