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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e38216e89dcd97a31456876ff58694230dfc67b2285c3540ff0677092d5db47
4
- data.tar.gz: 90fc4a982810cc11a85adc7276d69bffbc168d034bdda9e6147ac546e50c6dd5
3
+ metadata.gz: a0411122cd662e0f7e37bfeb21853e818ecc8ec6e91fa54ad21ead1fad9ac998
4
+ data.tar.gz: 4b62af5e3f1b1e4e252c31f97d488cec0ee2e59d2023761c2b69fb83c7afa8d1
5
5
  SHA512:
6
- metadata.gz: 6fe8289fad0d470fc1a664a5ec30d8e4c4de8ec6bd6500aa9e0c6fa87a96ad5279b3f7f842a1897e04f3c734f0c7ed38ba1592b58acfe4871152339ead2272e7
7
- data.tar.gz: eb9d243468bc8205fdde9f62f460355595eddd9bebc66b80ebab8e7435c3197ee4939c05531219d08c18ad59c2e28880b5a4b140ff9ecda8a47e54d0a0261169
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.7.0](https://www.ruby-lang.org)
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 = "mc_yourprivatekey"
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("mc_yourprivatekey")
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 = "mc_yourprivatekey"
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 rake
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.2"
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
- end
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.2
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-02-16 00:00:00.000000000 Z
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