mailclerk 1.0.2 → 1.1.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/README.md +85 -14
- data/lib/client.rb +62 -0
- data/lib/errors.rb +15 -0
- data/lib/mailclerk.rb +14 -66
- data/lib/outbox.rb +93 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0411122cd662e0f7e37bfeb21853e818ecc8ec6e91fa54ad21ead1fad9ac998
|
4
|
+
data.tar.gz: 4b62af5e3f1b1e4e252c31f97d488cec0ee2e59d2023761c2b69fb83c7afa8d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47d25d797fd25b415c8c251e464539df9544dd9863716ad37cc2b6bae843fe61f49c39f6853ff74d994239e920895db290282b84f64016672e590129bf443d37
|
7
|
+
data.tar.gz: 4eeea9f9278a145646f3fad23e0672c191c7b6b53ce148cf561dd7a76f268bfa729feec32bf5a0871270bf10c4f39d7aaac5896d237e0c202fb89aed24499186
|
data/README.md
CHANGED
@@ -16,8 +16,9 @@ Mailclerk helps anyone on your team design great emails, improve their performan
|
|
16
16
|
- [Setup](#setup)
|
17
17
|
- [API Key & URL](#api-key--url)
|
18
18
|
- [Usage](#usage)
|
19
|
+
- [Usage in Test Environments](#usage-in-test-environments)
|
19
20
|
- [Varying API Keys](#varying-api-keys)
|
20
|
-
- [Tests](#tests)
|
21
|
+
- [Gem Tests](#gem-tests)
|
21
22
|
- [Versioning](#versioning)
|
22
23
|
- [Code of Conduct](#code-of-conduct)
|
23
24
|
- [Contributions](#contributions)
|
@@ -28,7 +29,7 @@ Mailclerk helps anyone on your team design great emails, improve their performan
|
|
28
29
|
|
29
30
|
## Requirements
|
30
31
|
|
31
|
-
1. [Ruby 2.
|
32
|
+
1. [Ruby 2.4.0](https://www.ruby-lang.org)
|
32
33
|
|
33
34
|
## Setup
|
34
35
|
|
@@ -50,9 +51,9 @@ To set the Mailclerk API Key (begins with `mc_`), you can provide it as an
|
|
50
51
|
environmental variable: `MAILCLERK_API_KEY`. Alternatively, you can
|
51
52
|
set it directly on the Mailclerk module:
|
52
53
|
|
53
|
-
```
|
54
|
+
```ruby
|
54
55
|
# config/initializers/mailclerk.rb
|
55
|
-
Mailclerk.api_key = "
|
56
|
+
Mailclerk.api_key = "mc_live_yourprivatekey"
|
56
57
|
```
|
57
58
|
|
58
59
|
_If you are using version control like git, we strongly recommend storing your
|
@@ -67,44 +68,114 @@ You'll need an active account and at least one template (in the example `welcome
|
|
67
68
|
|
68
69
|
To send an email to "alice@example.com":
|
69
70
|
|
70
|
-
```
|
71
|
+
```ruby
|
71
72
|
Mailclerk.deliver("welcome-email", "alice@example.com")
|
73
|
+
Mailclerk.deliver("welcome-email", "Alice Adams <alice@example.com>")
|
74
|
+
Mailclerk.deliver("welcome-email", { name: "Alice Adams", address: "<alice@example.com>" })
|
72
75
|
```
|
73
76
|
|
74
77
|
If the template has any dynamic data, you can include it in the third parameter
|
75
78
|
as a hash:
|
76
79
|
|
77
|
-
```
|
80
|
+
```ruby
|
78
81
|
Mailclerk.deliver("welcome-email", "alice@example.com", { name: "Alice" })
|
79
82
|
```
|
80
83
|
|
81
84
|
See [Mailclerk documentation](https://dashboard.mailclerk.app/docs) for more details.
|
82
85
|
|
86
|
+
## Usage in Test Environments
|
87
|
+
|
88
|
+
Your Mailclerk environment has two API keys: a production key (beginning with `mc_live`)
|
89
|
+
and a test key (beginning with `mc_test`). If you use the test key, emails will
|
90
|
+
not be delivered, but will show up in the logs on your Mailclerk account and can be
|
91
|
+
previewed there. This replaces tools like [Letter Opener](https://github.com/ryanb/letter_opener) for previewing emails in development.
|
92
|
+
|
93
|
+
To avoid cluttering up your Mailclerk test logs with sends triggered by your
|
94
|
+
automated test suite, call `Mailclerk.outbox.enable` in the file that
|
95
|
+
configures your tests. For example, in Rspec with Rails, add:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
# spec/rails_helper.rb
|
99
|
+
Mailclerk.outbox.enable
|
100
|
+
```
|
101
|
+
|
102
|
+
This will also enable utility methods which you can use to write tests that check
|
103
|
+
emails are sent with the correct data:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
# Number of emails "sent"
|
107
|
+
Mailclerk.outbox.length
|
108
|
+
|
109
|
+
# Returns all emails of matching a template or email recipient. See method
|
110
|
+
Mailclerk.outbox.filter(template: "welcome-email")
|
111
|
+
Mailclerk.outbox.filter(recipient_email: "felix@example.com")
|
112
|
+
|
113
|
+
# Returns the most recent email (instance of Mailclerk::TestEmail):
|
114
|
+
email = Mailclerk.outbox.last
|
115
|
+
email.template # "welcome-email"
|
116
|
+
email.recipient_email # "felix@example.com"
|
117
|
+
email.subject # "Welcome to Acme Felix"
|
118
|
+
email.html # "<html><body>..."
|
119
|
+
```
|
120
|
+
|
121
|
+
In between test cases, you should clear the stored emails by calling `Mailclerk.outbox.reset`.
|
122
|
+
|
123
|
+
For example, in Rspec with Rails:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
# spec/rails_helper.rb
|
127
|
+
RSpec.configure do |config|
|
128
|
+
config.before(:each) do
|
129
|
+
Mailclerk.outbox.reset
|
130
|
+
end
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
`Mailclerk::OutboxEmail` has the following attributes:
|
135
|
+
|
136
|
+
| Attribute | Description |
|
137
|
+
| ----------------- | -------------------------------------------------------------------------- |
|
138
|
+
| `template` | Slug of the template sent (1st argument to `Mailclerk.deliver`) |
|
139
|
+
| `recipient` | Hash representing the send recipient (2nd argument to `Mailclerk.deliver`) |
|
140
|
+
| `recipient_email` | Email of the send recipient |
|
141
|
+
| `recipient_name` | Name of the send recipient (nil if not specified) |
|
142
|
+
| `data` | Dynamic data for the send (3rd argument to `Mailclerk.deliver`) |
|
143
|
+
| `options` | Options specified for the send (4th argument to `Mailclerk.deliver`) |
|
144
|
+
| `from` | From Mailclerk: Hash with `name` and `address` of the sender |
|
145
|
+
| `subject` | From Mailclerk: Text of the send's subject line |
|
146
|
+
| `preheader` | From Mailclerk: Text of the send's preheader |
|
147
|
+
| `html` | From Mailclerk: Rendered body HTML for the send |
|
148
|
+
| `text` | From Mailclerk: Rendered plaintext version of the send |
|
149
|
+
| `headers` | From Mailclerk: Extra email headers (e.g. `reply-to`) |
|
150
|
+
|
151
|
+
See the [Mailclerk testing documentation](https://dashboard.mailclerk.app/docs#testing)
|
152
|
+
for more details.
|
153
|
+
|
83
154
|
## Varying API Keys
|
84
155
|
|
85
156
|
If you need to use multiple API keys, you can also initialize `Mailclerk::Client`
|
86
157
|
instances with different keys. This:
|
87
158
|
|
88
|
-
```
|
89
|
-
mc_client = Mailclerk.new("
|
159
|
+
```ruby
|
160
|
+
mc_client = Mailclerk.new("mc_live_yourprivatekey")
|
90
161
|
mc_client.deliver("welcome-email", "bob@example.com")
|
91
162
|
```
|
92
163
|
|
93
164
|
Is equivalent to this:
|
94
165
|
|
95
|
-
```
|
96
|
-
Mailclerk.api_key = "
|
166
|
+
```ruby
|
167
|
+
Mailclerk.api_key = "mc_live_yourprivatekey"
|
97
168
|
Mailclerk.deliver("welcome-email", "bob@example.com")
|
98
169
|
```
|
99
170
|
|
100
|
-
## Tests
|
101
|
-
|
102
|
-
Tests aren't currently implemented. When they are, to test, run:
|
171
|
+
## Gem Tests
|
103
172
|
|
104
173
|
```
|
105
|
-
bundle exec
|
174
|
+
bundle exec rspec
|
106
175
|
```
|
107
176
|
|
177
|
+
Requires values in .env file as well
|
178
|
+
|
108
179
|
## Versioning
|
109
180
|
|
110
181
|
Read [Semantic Versioning](https://semver.org) for details. Briefly, it means:
|
data/lib/client.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
module Mailclerk
|
2
|
+
class Client
|
3
|
+
def initialize(api_key, api_url=nil)
|
4
|
+
@api_key = api_key
|
5
|
+
@api_url = api_url || ENV['MAILCLERK_API_URL'] || DEFAULT_API_URL
|
6
|
+
|
7
|
+
if @api_key.nil?
|
8
|
+
raise MailclerkError.new(
|
9
|
+
"No Mailclerk API Key provided. Set `Mailclerk.api_key`"
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
if @api_url.nil? || @api_url.empty?
|
14
|
+
raise MailclerkError.new("Mailclerk API URL empty")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def deliver(template, recipient, data={}, options={})
|
19
|
+
conn = Faraday.new(url: @api_url)
|
20
|
+
conn.basic_auth(@api_key, '')
|
21
|
+
|
22
|
+
if Mailclerk.outbox_enabled?
|
23
|
+
options = options.merge(
|
24
|
+
"local_outbox" => true
|
25
|
+
)
|
26
|
+
options.delete(:local_outbox)
|
27
|
+
end
|
28
|
+
|
29
|
+
params = {
|
30
|
+
'template' => template,
|
31
|
+
'recipient' => recipient,
|
32
|
+
'data' => data,
|
33
|
+
'options' => options
|
34
|
+
}
|
35
|
+
|
36
|
+
response = conn.post('deliver', params.to_json, {
|
37
|
+
'Content-Type' => 'application/json',
|
38
|
+
'X-Client-Version' => Identity.version_label
|
39
|
+
})
|
40
|
+
|
41
|
+
if response.status >= 400
|
42
|
+
begin
|
43
|
+
message = JSON.parse(response.body)["message"] || "Unknown"
|
44
|
+
description = "Mailclerk API Error: #{ message }"
|
45
|
+
rescue JSON::ParserError
|
46
|
+
description = "Mailclerk API Unknown Error"
|
47
|
+
end
|
48
|
+
|
49
|
+
raise MailclerkAPIError.new(
|
50
|
+
description, response.status, response
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
if Mailclerk.outbox_enabled?
|
55
|
+
params["options"].delete("local_outbox")
|
56
|
+
Mailclerk.outbox.add_send(params, JSON.parse(response.body)["delivery"])
|
57
|
+
end
|
58
|
+
|
59
|
+
return response
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/errors.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Mailclerk
|
2
|
+
class MailclerkError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class MailclerkAPIError < MailclerkError
|
6
|
+
attr_accessor :http_status
|
7
|
+
attr_accessor :http_response
|
8
|
+
|
9
|
+
def initialize(description, http_status=nil, http_response=nil)
|
10
|
+
super(description)
|
11
|
+
self.http_status = http_status
|
12
|
+
self.http_response = http_response
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/mailclerk.rb
CHANGED
@@ -3,6 +3,10 @@
|
|
3
3
|
require 'faraday'
|
4
4
|
require 'json'
|
5
5
|
|
6
|
+
require "client"
|
7
|
+
require "errors"
|
8
|
+
require "outbox"
|
9
|
+
|
6
10
|
module Mailclerk
|
7
11
|
DEFAULT_API_URL = "https://api.mailclerk.app"
|
8
12
|
|
@@ -22,7 +26,7 @@ module Mailclerk
|
|
22
26
|
end
|
23
27
|
|
24
28
|
def self.version
|
25
|
-
"1.0
|
29
|
+
"1.1.0"
|
26
30
|
end
|
27
31
|
|
28
32
|
def self.version_label
|
@@ -30,75 +34,19 @@ module Mailclerk
|
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
33
|
-
class MailclerkError < StandardError
|
34
|
-
end
|
35
|
-
|
36
|
-
class MailclerkAPIError < MailclerkError
|
37
|
-
attr_accessor :http_status
|
38
|
-
attr_accessor :http_response
|
39
|
-
|
40
|
-
def initialize(description, http_status=nil, http_response=nil)
|
41
|
-
super(description)
|
42
|
-
self.http_status = http_status
|
43
|
-
self.http_response = http_response
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
class Client
|
49
|
-
def initialize(api_key, api_url=nil)
|
50
|
-
@api_key = api_key
|
51
|
-
@api_url = api_url || ENV['MAILCLERK_API_URL'] || DEFAULT_API_URL
|
52
|
-
|
53
|
-
if @api_key.nil?
|
54
|
-
raise MailclerkError.new(
|
55
|
-
"No Mailclerk API Key provided. Set `Mailclerk.api_key`"
|
56
|
-
)
|
57
|
-
end
|
58
|
-
|
59
|
-
if @api_url.nil? || @api_url.empty?
|
60
|
-
raise MailclerkError.new("Mailclerk API URL empty")
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def deliver(template, recipient, data={}, options={})
|
65
|
-
conn = Faraday.new(url: @api_url)
|
66
|
-
conn.basic_auth(@api_key, '')
|
67
|
-
|
68
|
-
response = conn.post('deliver', {
|
69
|
-
'template' => template,
|
70
|
-
'recipient' => recipient,
|
71
|
-
'data' => data,
|
72
|
-
'options' => options
|
73
|
-
}.to_json, {
|
74
|
-
'Content-Type' => 'application/json',
|
75
|
-
'X-Client-Version' => Identity.version_label
|
76
|
-
})
|
77
|
-
|
78
|
-
if response.status >= 400
|
79
|
-
begin
|
80
|
-
message = JSON.parse(response.body)["message"] || "Unknown"
|
81
|
-
description = "Mailclerk API Error: #{ message }"
|
82
|
-
rescue JSON::ParserError
|
83
|
-
description = "Mailclerk API Unknown Error"
|
84
|
-
end
|
85
|
-
|
86
|
-
raise MailclerkAPIError.new(
|
87
|
-
description, response.status, response
|
88
|
-
)
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
return response
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
37
|
# Syntax intended to emulate ActionMailer
|
97
38
|
def self.deliver(*args)
|
98
39
|
api_key = self.api_key || ENV['MAILCLERK_API_KEY']
|
99
40
|
|
100
|
-
client = Client.new(api_key, self.api_url)
|
41
|
+
client = Mailclerk::Client.new(api_key, self.api_url)
|
101
42
|
return client.deliver(*args)
|
102
43
|
end
|
44
|
+
|
45
|
+
def self.outbox
|
46
|
+
@outbox ||= Mailclerk::Outbox.new
|
47
|
+
end
|
103
48
|
|
104
|
-
|
49
|
+
def self.outbox_enabled?
|
50
|
+
!!(@outbox && @outbox.enabled)
|
51
|
+
end
|
52
|
+
end
|
data/lib/outbox.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Mailclerk
|
2
|
+
class Outbox < Array
|
3
|
+
attr_accessor :enabled
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
self.enabled = false
|
7
|
+
end
|
8
|
+
|
9
|
+
def enable
|
10
|
+
self.enabled = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset
|
14
|
+
self.clear
|
15
|
+
end
|
16
|
+
|
17
|
+
# Not just an alias for 'select'
|
18
|
+
def filter(query)
|
19
|
+
puts query
|
20
|
+
self.select do |email|
|
21
|
+
query.all? do |key, value|
|
22
|
+
puts email[key]
|
23
|
+
email[key] == value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_send(request, response)
|
29
|
+
email = OutboxEmail.new(
|
30
|
+
OutboxEmail.recursive_init(
|
31
|
+
response.merge(request)
|
32
|
+
)
|
33
|
+
)
|
34
|
+
self << email
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class OutboxEmail < OpenStruct
|
39
|
+
|
40
|
+
def self.recursive_init(data)
|
41
|
+
|
42
|
+
data.each do |key, val|
|
43
|
+
if val.is_a?(Hash)
|
44
|
+
data[key] = self.recursive_init(val)
|
45
|
+
else
|
46
|
+
data[key] = val
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
return OpenStruct.new(data)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Custom getters
|
54
|
+
|
55
|
+
def recipient_email
|
56
|
+
return parse_recipient[:address]
|
57
|
+
end
|
58
|
+
|
59
|
+
def recipient_name
|
60
|
+
return parse_recipient[:name]
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def parse_recipient
|
66
|
+
return {} unless self.recipient
|
67
|
+
|
68
|
+
if self.recipient.is_a?(OpenStruct)
|
69
|
+
return self.recipient
|
70
|
+
end
|
71
|
+
|
72
|
+
text = self.recipient.strip
|
73
|
+
|
74
|
+
if text =~ /^[^<]+<[^<]+>$/
|
75
|
+
parts = text.split("<", 2);
|
76
|
+
|
77
|
+
name = parts[0].strip.gsub('"', "")
|
78
|
+
|
79
|
+
address = parts[1].strip.gsub(">", "")
|
80
|
+
|
81
|
+
return {
|
82
|
+
name: name,
|
83
|
+
address: address
|
84
|
+
}
|
85
|
+
else
|
86
|
+
return {
|
87
|
+
name: nil,
|
88
|
+
address: text
|
89
|
+
}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mailclerk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noah Litvin
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-
|
12
|
+
date: 2021-03-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|
@@ -109,6 +109,20 @@ dependencies:
|
|
109
109
|
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '3.9'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: dotenv
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
112
126
|
description:
|
113
127
|
email:
|
114
128
|
- developers@mailclerk.app
|
@@ -120,7 +134,10 @@ extra_rdoc_files:
|
|
120
134
|
files:
|
121
135
|
- LICENSE.md
|
122
136
|
- README.md
|
137
|
+
- lib/client.rb
|
138
|
+
- lib/errors.rb
|
123
139
|
- lib/mailclerk.rb
|
140
|
+
- lib/outbox.rb
|
124
141
|
homepage: https://github.com/mailclerk/mailclerk-ruby
|
125
142
|
licenses:
|
126
143
|
- MIT
|