emailit 2.0.1
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +597 -0
- data/lib/emailit/api_resource.rb +22 -0
- data/lib/emailit/api_response.rb +18 -0
- data/lib/emailit/base_client.rb +115 -0
- data/lib/emailit/collection.rb +25 -0
- data/lib/emailit/delivery_method.rb +74 -0
- data/lib/emailit/emailit_client.rb +53 -0
- data/lib/emailit/emailit_object.rb +57 -0
- data/lib/emailit/errors.rb +36 -0
- data/lib/emailit/events/webhook_event.rb +215 -0
- data/lib/emailit/railtie.rb +13 -0
- data/lib/emailit/resources/api_key.rb +7 -0
- data/lib/emailit/resources/audience.rb +7 -0
- data/lib/emailit/resources/contact.rb +7 -0
- data/lib/emailit/resources/domain.rb +7 -0
- data/lib/emailit/resources/email.rb +7 -0
- data/lib/emailit/resources/email_verification.rb +7 -0
- data/lib/emailit/resources/email_verification_list.rb +7 -0
- data/lib/emailit/resources/event.rb +7 -0
- data/lib/emailit/resources/subscriber.rb +7 -0
- data/lib/emailit/resources/suppression.rb +7 -0
- data/lib/emailit/resources/template.rb +7 -0
- data/lib/emailit/resources/webhook.rb +7 -0
- data/lib/emailit/services/api_key_service.rb +27 -0
- data/lib/emailit/services/audience_service.rb +27 -0
- data/lib/emailit/services/base_service.rb +50 -0
- data/lib/emailit/services/contact_service.rb +27 -0
- data/lib/emailit/services/domain_service.rb +31 -0
- data/lib/emailit/services/email_service.rb +47 -0
- data/lib/emailit/services/email_verification_list_service.rb +27 -0
- data/lib/emailit/services/email_verification_service.rb +11 -0
- data/lib/emailit/services/event_service.rb +15 -0
- data/lib/emailit/services/subscriber_service.rb +27 -0
- data/lib/emailit/services/suppression_service.rb +27 -0
- data/lib/emailit/services/template_service.rb +31 -0
- data/lib/emailit/services/webhook_service.rb +27 -0
- data/lib/emailit/util.rb +35 -0
- data/lib/emailit/version.rb +5 -0
- data/lib/emailit/webhook_signature.rb +59 -0
- data/lib/emailit.rb +66 -0
- metadata +144 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: fc40658f338dd2cc6a1dfc86a17d8db107893a15d9091dad28c27fabbcd17140
|
|
4
|
+
data.tar.gz: 9f43b54e4f0d413317ac3257222b42756bd699fd5b938aa01d11017062611dbd
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: aac6bc7aeb78bbdefaf8d693911f35760ee146f047ce4b0f7dfdce042249d35f96cf4c182c2690b00f0d95f5ec8f6e8a5a8456f832c4770b78c8ddc5adef6404
|
|
7
|
+
data.tar.gz: b3d52849c286a6d39914ec61fb03ab8c94139055e2954d4938ab5a6c7e799a8292b206db8a4b9b1b8c364efe74f0403d8ffb88377beb2a4b0a755ce8754ca430
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Emailit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
# Emailit Ruby
|
|
2
|
+
|
|
3
|
+
[](https://github.com/emailit/emailit-ruby/actions)
|
|
4
|
+
[](https://rubygems.org/gems/emailit)
|
|
5
|
+
[](https://github.com/emailit/emailit-ruby/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
The official Ruby and Rails SDK for the [Emailit](https://emailit.com) Email API.
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Ruby 3.0+
|
|
12
|
+
- No external dependencies (uses `net/http` from stdlib)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
gem install emailit
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or add to your Gemfile:
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
gem "emailit"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Getting Started
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
require "emailit"
|
|
30
|
+
|
|
31
|
+
client = Emailit::EmailitClient.new("your_api_key")
|
|
32
|
+
|
|
33
|
+
email = client.emails.send(
|
|
34
|
+
from: "hello@yourdomain.com",
|
|
35
|
+
to: ["user@example.com"],
|
|
36
|
+
subject: "Hello from Emailit",
|
|
37
|
+
html: "<h1>Welcome!</h1><p>Thanks for signing up.</p>"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
puts email.id # em_abc123...
|
|
41
|
+
puts email.status # pending
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
All service methods return typed resource objects (`Email`, `Domain`, `Contact`, etc.) with direct property access -- just like the Stripe SDK.
|
|
45
|
+
|
|
46
|
+
## Available Services
|
|
47
|
+
|
|
48
|
+
| Service | Method | Description |
|
|
49
|
+
|---------|--------|-------------|
|
|
50
|
+
| Emails | `client.emails` | Send, list, get, cancel, retry emails |
|
|
51
|
+
| Domains | `client.domains` | Create, verify, list, manage sending domains |
|
|
52
|
+
| API Keys | `client.api_keys` | Create, list, manage API keys |
|
|
53
|
+
| Audiences | `client.audiences` | Create, list, manage audiences |
|
|
54
|
+
| Subscribers | `client.subscribers` | Add, list, manage subscribers in audiences |
|
|
55
|
+
| Templates | `client.templates` | Create, list, publish email templates |
|
|
56
|
+
| Suppressions | `client.suppressions` | Create, list, manage suppressed addresses |
|
|
57
|
+
| Email Verifications | `client.email_verifications` | Verify email addresses |
|
|
58
|
+
| Email Verification Lists | `client.email_verification_lists` | Create, list, get results, export |
|
|
59
|
+
| Webhooks | `client.webhooks` | Create, list, manage webhooks |
|
|
60
|
+
| Contacts | `client.contacts` | Create, list, manage contacts |
|
|
61
|
+
| Events | `client.events` | List and retrieve events |
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
### Emails
|
|
66
|
+
|
|
67
|
+
#### Send an email
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
email = client.emails.send(
|
|
71
|
+
from: "hello@yourdomain.com",
|
|
72
|
+
to: ["user@example.com"],
|
|
73
|
+
subject: "Hello from Emailit",
|
|
74
|
+
html: "<h1>Welcome!</h1>"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
puts email.id
|
|
78
|
+
puts email.status
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### Send with a template
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
email = client.emails.send(
|
|
85
|
+
from: "hello@yourdomain.com",
|
|
86
|
+
to: "user@example.com",
|
|
87
|
+
template: "welcome_email",
|
|
88
|
+
variables: {
|
|
89
|
+
name: "John Doe",
|
|
90
|
+
company: "Acme Inc"
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Send with attachments
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
email = client.emails.send(
|
|
99
|
+
from: "invoices@yourdomain.com",
|
|
100
|
+
to: "customer@example.com",
|
|
101
|
+
subject: "Your Invoice #12345",
|
|
102
|
+
html: "<p>Please find your invoice attached.</p>",
|
|
103
|
+
attachments: [
|
|
104
|
+
{
|
|
105
|
+
filename: "invoice.pdf",
|
|
106
|
+
content: Base64.strict_encode64(File.read("invoice.pdf")),
|
|
107
|
+
content_type: "application/pdf"
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### Schedule an email
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
email = client.emails.send(
|
|
117
|
+
from: "reminders@yourdomain.com",
|
|
118
|
+
to: "user@example.com",
|
|
119
|
+
subject: "Appointment Reminder",
|
|
120
|
+
html: "<p>Your appointment is tomorrow at 2 PM.</p>",
|
|
121
|
+
scheduled_at: "2026-01-10T09:00:00Z"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
puts email.status # scheduled
|
|
125
|
+
puts email.scheduled_at # 2026-01-10T09:00:00Z
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### List emails
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
emails = client.emails.list(page: 1, limit: 10)
|
|
132
|
+
|
|
133
|
+
emails.each do |email|
|
|
134
|
+
puts "#{email.id} — #{email.status}"
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
if emails.has_more?
|
|
138
|
+
# fetch next page
|
|
139
|
+
end
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### Cancel / Retry
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
client.emails.cancel("em_abc123")
|
|
146
|
+
client.emails.retry("em_abc123")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### Domains
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
# Create a domain
|
|
155
|
+
domain = client.domains.create(
|
|
156
|
+
name: "example.com",
|
|
157
|
+
track_loads: true,
|
|
158
|
+
track_clicks: true
|
|
159
|
+
)
|
|
160
|
+
puts domain.id
|
|
161
|
+
|
|
162
|
+
# Verify DNS
|
|
163
|
+
domain = client.domains.verify("sd_123")
|
|
164
|
+
|
|
165
|
+
# List all domains
|
|
166
|
+
domains = client.domains.list
|
|
167
|
+
|
|
168
|
+
# Get a domain
|
|
169
|
+
domain = client.domains.get("sd_123")
|
|
170
|
+
|
|
171
|
+
# Update a domain
|
|
172
|
+
domain = client.domains.update("sd_123", track_clicks: false)
|
|
173
|
+
|
|
174
|
+
# Delete a domain
|
|
175
|
+
client.domains.delete("sd_123")
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
### API Keys
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
# Create an API key
|
|
184
|
+
key = client.api_keys.create(
|
|
185
|
+
name: "Production Key",
|
|
186
|
+
scope: "full"
|
|
187
|
+
)
|
|
188
|
+
puts key.key # only available on create
|
|
189
|
+
|
|
190
|
+
# List all API keys
|
|
191
|
+
keys = client.api_keys.list
|
|
192
|
+
|
|
193
|
+
# Get an API key
|
|
194
|
+
key = client.api_keys.get("ak_123")
|
|
195
|
+
|
|
196
|
+
# Update an API key
|
|
197
|
+
client.api_keys.update("ak_123", name: "Renamed Key")
|
|
198
|
+
|
|
199
|
+
# Delete an API key
|
|
200
|
+
client.api_keys.delete("ak_123")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### Audiences
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
# Create an audience
|
|
209
|
+
audience = client.audiences.create(name: "Newsletter")
|
|
210
|
+
puts audience.id
|
|
211
|
+
puts audience.token
|
|
212
|
+
|
|
213
|
+
# List audiences
|
|
214
|
+
audiences = client.audiences.list
|
|
215
|
+
|
|
216
|
+
# Get an audience
|
|
217
|
+
audience = client.audiences.get("aud_123")
|
|
218
|
+
|
|
219
|
+
# Update an audience
|
|
220
|
+
client.audiences.update("aud_123", name: "Updated Newsletter")
|
|
221
|
+
|
|
222
|
+
# Delete an audience
|
|
223
|
+
client.audiences.delete("aud_123")
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
### Subscribers
|
|
229
|
+
|
|
230
|
+
Subscribers belong to an audience, so the audience ID is always the first argument.
|
|
231
|
+
|
|
232
|
+
```ruby
|
|
233
|
+
# Add a subscriber
|
|
234
|
+
subscriber = client.subscribers.create("aud_123",
|
|
235
|
+
email: "user@example.com",
|
|
236
|
+
first_name: "John",
|
|
237
|
+
last_name: "Doe"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# List subscribers in an audience
|
|
241
|
+
subscribers = client.subscribers.list("aud_123")
|
|
242
|
+
|
|
243
|
+
# Get a subscriber
|
|
244
|
+
subscriber = client.subscribers.get("aud_123", "sub_456")
|
|
245
|
+
|
|
246
|
+
# Update a subscriber
|
|
247
|
+
client.subscribers.update("aud_123", "sub_456", first_name: "Jane")
|
|
248
|
+
|
|
249
|
+
# Delete a subscriber
|
|
250
|
+
client.subscribers.delete("aud_123", "sub_456")
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
### Templates
|
|
256
|
+
|
|
257
|
+
```ruby
|
|
258
|
+
# Create a template
|
|
259
|
+
result = client.templates.create(
|
|
260
|
+
name: "Welcome",
|
|
261
|
+
subject: "Welcome!",
|
|
262
|
+
html: "<h1>Hi {{name}}</h1>"
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# List templates
|
|
266
|
+
templates = client.templates.list
|
|
267
|
+
|
|
268
|
+
# Get a template
|
|
269
|
+
template = client.templates.get("tem_123")
|
|
270
|
+
|
|
271
|
+
# Update a template
|
|
272
|
+
client.templates.update("tem_123", subject: "New Subject")
|
|
273
|
+
|
|
274
|
+
# Publish a template
|
|
275
|
+
client.templates.publish("tem_123")
|
|
276
|
+
|
|
277
|
+
# Delete a template
|
|
278
|
+
client.templates.delete("tem_123")
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### Suppressions
|
|
284
|
+
|
|
285
|
+
```ruby
|
|
286
|
+
# Create a suppression
|
|
287
|
+
suppression = client.suppressions.create(
|
|
288
|
+
email: "spam@example.com",
|
|
289
|
+
type: "hard_bounce",
|
|
290
|
+
reason: "Manual suppression"
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# List suppressions
|
|
294
|
+
suppressions = client.suppressions.list
|
|
295
|
+
|
|
296
|
+
# Get a suppression
|
|
297
|
+
suppression = client.suppressions.get("sup_123")
|
|
298
|
+
|
|
299
|
+
# Update a suppression
|
|
300
|
+
client.suppressions.update("sup_123", reason: "Updated")
|
|
301
|
+
|
|
302
|
+
# Delete a suppression
|
|
303
|
+
client.suppressions.delete("sup_123")
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
### Email Verifications
|
|
309
|
+
|
|
310
|
+
```ruby
|
|
311
|
+
result = client.email_verifications.verify(email: "test@example.com")
|
|
312
|
+
|
|
313
|
+
puts result.status # valid
|
|
314
|
+
puts result.score # 0.95
|
|
315
|
+
puts result.risk # low
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
### Email Verification Lists
|
|
321
|
+
|
|
322
|
+
```ruby
|
|
323
|
+
# Create a verification list
|
|
324
|
+
list = client.email_verification_lists.create(
|
|
325
|
+
name: "Marketing List Q1",
|
|
326
|
+
emails: [
|
|
327
|
+
"user1@example.com",
|
|
328
|
+
"user2@example.com",
|
|
329
|
+
"user3@example.com"
|
|
330
|
+
]
|
|
331
|
+
)
|
|
332
|
+
puts list.id # evl_abc123...
|
|
333
|
+
puts list.status # pending
|
|
334
|
+
|
|
335
|
+
# List all verification lists
|
|
336
|
+
lists = client.email_verification_lists.list
|
|
337
|
+
|
|
338
|
+
# Get a verification list
|
|
339
|
+
list = client.email_verification_lists.get("evl_abc123")
|
|
340
|
+
puts list.stats["successful_verifications"]
|
|
341
|
+
|
|
342
|
+
# Get verification results
|
|
343
|
+
results = client.email_verification_lists.results("evl_abc123", page: 1, limit: 50)
|
|
344
|
+
|
|
345
|
+
results.each do |result|
|
|
346
|
+
puts "#{result.email} — #{result.result}"
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Export results as XLSX
|
|
350
|
+
response = client.email_verification_lists.export("evl_abc123")
|
|
351
|
+
File.write("results.xlsx", response.body)
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
### Webhooks
|
|
357
|
+
|
|
358
|
+
```ruby
|
|
359
|
+
# Create a webhook
|
|
360
|
+
webhook = client.webhooks.create(
|
|
361
|
+
name: "My Webhook",
|
|
362
|
+
url: "https://example.com/hook",
|
|
363
|
+
all_events: true,
|
|
364
|
+
enabled: true
|
|
365
|
+
)
|
|
366
|
+
puts webhook.id
|
|
367
|
+
|
|
368
|
+
# List webhooks
|
|
369
|
+
webhooks = client.webhooks.list
|
|
370
|
+
|
|
371
|
+
# Get a webhook
|
|
372
|
+
webhook = client.webhooks.get("wh_123")
|
|
373
|
+
|
|
374
|
+
# Update a webhook
|
|
375
|
+
client.webhooks.update("wh_123", enabled: false)
|
|
376
|
+
|
|
377
|
+
# Delete a webhook
|
|
378
|
+
client.webhooks.delete("wh_123")
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
### Contacts
|
|
384
|
+
|
|
385
|
+
```ruby
|
|
386
|
+
# Create a contact
|
|
387
|
+
contact = client.contacts.create(
|
|
388
|
+
email: "user@example.com",
|
|
389
|
+
first_name: "John",
|
|
390
|
+
last_name: "Doe"
|
|
391
|
+
)
|
|
392
|
+
puts contact.id
|
|
393
|
+
|
|
394
|
+
# List contacts
|
|
395
|
+
contacts = client.contacts.list
|
|
396
|
+
|
|
397
|
+
# Get a contact
|
|
398
|
+
contact = client.contacts.get("con_123")
|
|
399
|
+
|
|
400
|
+
# Update a contact
|
|
401
|
+
client.contacts.update("con_123", first_name: "Jane")
|
|
402
|
+
|
|
403
|
+
# Delete a contact
|
|
404
|
+
client.contacts.delete("con_123")
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
### Events
|
|
410
|
+
|
|
411
|
+
```ruby
|
|
412
|
+
# List events
|
|
413
|
+
events = client.events.list(type: "email.delivered")
|
|
414
|
+
|
|
415
|
+
events.each do |event|
|
|
416
|
+
puts event.type
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# Get an event
|
|
420
|
+
event = client.events.get("evt_123")
|
|
421
|
+
puts event.type
|
|
422
|
+
puts event.data["email_id"]
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
## Webhook Events
|
|
426
|
+
|
|
427
|
+
The SDK provides typed event classes for all Emailit webhook event types under the `Emailit::Events` namespace, plus a `WebhookSignature` class for verifying webhook request signatures.
|
|
428
|
+
|
|
429
|
+
### Verifying Webhook Signatures
|
|
430
|
+
|
|
431
|
+
```ruby
|
|
432
|
+
require "emailit"
|
|
433
|
+
|
|
434
|
+
raw_body = request.body.read
|
|
435
|
+
signature = request.headers["X-Emailit-Signature"]
|
|
436
|
+
timestamp = request.headers["X-Emailit-Timestamp"]
|
|
437
|
+
secret = "your_webhook_signing_secret"
|
|
438
|
+
|
|
439
|
+
begin
|
|
440
|
+
event = Emailit::WebhookSignature.verify(raw_body, signature, timestamp, secret)
|
|
441
|
+
|
|
442
|
+
# event is automatically typed based on the event type
|
|
443
|
+
puts event.type # e.g. "email.delivered"
|
|
444
|
+
puts event.event_id # e.g. "evt_abc123"
|
|
445
|
+
|
|
446
|
+
# Access the event data
|
|
447
|
+
data = event.event_data
|
|
448
|
+
|
|
449
|
+
case event
|
|
450
|
+
when Emailit::Events::EmailDelivered
|
|
451
|
+
handle_delivered(event)
|
|
452
|
+
when Emailit::Events::EmailBounced
|
|
453
|
+
handle_bounce(event)
|
|
454
|
+
when Emailit::Events::ContactCreated
|
|
455
|
+
handle_new_contact(event)
|
|
456
|
+
else
|
|
457
|
+
puts "Unhandled: #{event.type}"
|
|
458
|
+
end
|
|
459
|
+
rescue Emailit::ApiError => e
|
|
460
|
+
render plain: e.message, status: 401
|
|
461
|
+
end
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
You can disable replay protection by passing `tolerance: nil`, or set a custom tolerance in seconds:
|
|
465
|
+
|
|
466
|
+
```ruby
|
|
467
|
+
# Skip replay check
|
|
468
|
+
event = Emailit::WebhookSignature.verify(raw_body, signature, timestamp, secret, tolerance: nil)
|
|
469
|
+
|
|
470
|
+
# Custom 10-minute tolerance
|
|
471
|
+
event = Emailit::WebhookSignature.verify(raw_body, signature, timestamp, secret, tolerance: 600)
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Available Event Types
|
|
475
|
+
|
|
476
|
+
**Emails:** `email.accepted`, `email.scheduled`, `email.delivered`, `email.bounced`, `email.attempted`, `email.failed`, `email.rejected`, `email.suppressed`, `email.received`, `email.complained`, `email.clicked`, `email.loaded`
|
|
477
|
+
|
|
478
|
+
**Domains:** `domain.created`, `domain.updated`, `domain.deleted`
|
|
479
|
+
|
|
480
|
+
**Audiences:** `audience.created`, `audience.updated`, `audience.deleted`
|
|
481
|
+
|
|
482
|
+
**Subscribers:** `subscriber.created`, `subscriber.updated`, `subscriber.deleted`
|
|
483
|
+
|
|
484
|
+
**Contacts:** `contact.created`, `contact.updated`, `contact.deleted`
|
|
485
|
+
|
|
486
|
+
**Templates:** `template.created`, `template.updated`, `template.deleted`
|
|
487
|
+
|
|
488
|
+
**Suppressions:** `suppression.created`, `suppression.updated`, `suppression.deleted`
|
|
489
|
+
|
|
490
|
+
**Email Verifications:** `email_verification.created`, `email_verification.updated`, `email_verification.deleted`
|
|
491
|
+
|
|
492
|
+
**Email Verification Lists:** `email_verification_list.created`, `email_verification_list.updated`, `email_verification_list.deleted`
|
|
493
|
+
|
|
494
|
+
Each event type has a corresponding class under `Emailit::Events::` (e.g. `Emailit::Events::EmailDelivered`, `Emailit::Events::DomainCreated`). You can use `is_a?` checks or the `EVENT_TYPE` constant for routing:
|
|
495
|
+
|
|
496
|
+
```ruby
|
|
497
|
+
case event
|
|
498
|
+
when Emailit::Events::EmailDelivered
|
|
499
|
+
handle_delivered(event)
|
|
500
|
+
when Emailit::Events::EmailBounced
|
|
501
|
+
handle_bounce(event)
|
|
502
|
+
when Emailit::Events::ContactCreated
|
|
503
|
+
handle_new_contact(event)
|
|
504
|
+
else
|
|
505
|
+
puts "Unhandled: #{event.type}"
|
|
506
|
+
end
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
## Ruby on Rails (ActionMailer)
|
|
510
|
+
|
|
511
|
+
The SDK natively supports Ruby on Rails via ActionMailer. When Rails is detected, a `:emailit` delivery method is automatically registered.
|
|
512
|
+
|
|
513
|
+
### Configuration
|
|
514
|
+
|
|
515
|
+
```ruby
|
|
516
|
+
# config/environments/production.rb
|
|
517
|
+
config.action_mailer.delivery_method = :emailit
|
|
518
|
+
config.action_mailer.emailit_settings = { api_key: ENV["EMAILIT_API_KEY"] }
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Usage
|
|
522
|
+
|
|
523
|
+
Once configured, all your existing mailers work with Emailit automatically:
|
|
524
|
+
|
|
525
|
+
```ruby
|
|
526
|
+
class UserMailer < ApplicationMailer
|
|
527
|
+
def welcome(user)
|
|
528
|
+
@user = user
|
|
529
|
+
mail(
|
|
530
|
+
to: @user.email,
|
|
531
|
+
subject: "Welcome to our app!"
|
|
532
|
+
)
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
# Send it
|
|
537
|
+
UserMailer.welcome(user).deliver_now
|
|
538
|
+
UserMailer.welcome(user).deliver_later
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
The delivery method automatically converts `Mail::Message` objects to Emailit API params, including:
|
|
542
|
+
|
|
543
|
+
- `from`, `to`, `cc`, `bcc`, `reply_to`
|
|
544
|
+
- `subject`
|
|
545
|
+
- HTML and plain-text bodies (multipart supported)
|
|
546
|
+
- File attachments (base64-encoded)
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
```ruby
|
|
550
|
+
class NotificationMailer < ApplicationMailer
|
|
551
|
+
def invoice(user, pdf_data)
|
|
552
|
+
attachments["invoice.pdf"] = {
|
|
553
|
+
mime_type: "application/pdf",
|
|
554
|
+
content: pdf_data
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
mail(
|
|
558
|
+
to: user.email,
|
|
559
|
+
subject: "Your Invoice"
|
|
560
|
+
)
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
## Error Handling
|
|
566
|
+
|
|
567
|
+
The SDK raises typed exceptions for API errors:
|
|
568
|
+
|
|
569
|
+
```ruby
|
|
570
|
+
begin
|
|
571
|
+
client.emails.send(
|
|
572
|
+
from: "hello@yourdomain.com",
|
|
573
|
+
to: "user@example.com",
|
|
574
|
+
subject: "Hello",
|
|
575
|
+
html: "<h1>Hi</h1>"
|
|
576
|
+
)
|
|
577
|
+
rescue Emailit::AuthenticationError => e
|
|
578
|
+
# Invalid API key (401)
|
|
579
|
+
rescue Emailit::InvalidRequestError => e
|
|
580
|
+
# Bad request or not found (400, 404)
|
|
581
|
+
rescue Emailit::RateLimitError => e
|
|
582
|
+
# Too many requests (429)
|
|
583
|
+
rescue Emailit::UnprocessableEntityError => e
|
|
584
|
+
# Validation failed (422)
|
|
585
|
+
rescue Emailit::ConnectionError => e
|
|
586
|
+
# Network error
|
|
587
|
+
rescue Emailit::ApiError => e
|
|
588
|
+
# Any other API error
|
|
589
|
+
puts e.http_status
|
|
590
|
+
puts e.http_body
|
|
591
|
+
puts e.json_body
|
|
592
|
+
end
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
## License
|
|
596
|
+
|
|
597
|
+
MIT -- see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emailit
|
|
4
|
+
class ApiResource < EmailitObject
|
|
5
|
+
OBJECT_NAME = ""
|
|
6
|
+
|
|
7
|
+
def self.class_url
|
|
8
|
+
"/v2/#{self::OBJECT_NAME}s"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.resource_url(id)
|
|
12
|
+
"#{class_url}/#{CGI.escape(id)}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def instance_url
|
|
16
|
+
id = self["id"]
|
|
17
|
+
raise "Could not determine instance URL: #{self.class} has no 'id'." unless id
|
|
18
|
+
|
|
19
|
+
self.class.resource_url(id)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emailit
|
|
4
|
+
class ApiResponse
|
|
5
|
+
attr_reader :status_code, :headers, :body, :json
|
|
6
|
+
|
|
7
|
+
def initialize(status_code, headers, body)
|
|
8
|
+
@status_code = status_code
|
|
9
|
+
@headers = headers
|
|
10
|
+
@body = body
|
|
11
|
+
@json = begin
|
|
12
|
+
JSON.parse(body)
|
|
13
|
+
rescue JSON::ParserError
|
|
14
|
+
nil
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|