mailclerk 0.1.1 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0746f6e459e89ebf5c23c33c940f10f4639d7b92e9bffbb7bb0f0c217608d8e9
4
- data.tar.gz: 12c12b1846326a577d6423dd7b20ecf77156c50d4e3ab084327b72224a4b8023
3
+ metadata.gz: 97393aafed17d2eb1ca2d9c8242154c116e3bbb58e60596efd5f03b8697fb7df
4
+ data.tar.gz: 65cf703eede9e9213f0a7cb439dbed5e908cb127184634002a7618d0b7cfff8d
5
5
  SHA512:
6
- metadata.gz: 1867bff480e230a049d3ec3f14221ca83ace81ed745cbefd1b3b7ef7ec6d6d561f7b8f9fe37b9d0d83d178f50ed28061bf6f35768f806dd4e9d27997a7f6c289
7
- data.tar.gz: 5aa6071e289c6194fe43abfba94ed141200b1c385c42ac897e4c09dd0b0bf722f079f7e69b0d96d767deac7273a47a5475b31d60aac3160575dfb431e0006ffa
6
+ metadata.gz: 0f6fac55f44d59eb8fbd49709117543d666a26f53b9f650c89b14c04705b62d82df88c7ff5ea447dcddba692bd73c6d5d381725e54956de130a8a2c1949d0bdd
7
+ data.tar.gz: 81906cfdb4a73edbad522ef11fc75354d3dc97d9c03b26ed693c398fdaa5646b74ab113d3cb66e7188887c108a037e0b2b6c93d0762481468e1a7ede6a1afafc
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="mailcerk.png" alt="Mailclerk Logo"/>
2
+ <img src="https://github.com/mailclerk/mailclerk-ruby/blob/main/mailclerk.png?raw=true" alt="Mailclerk Logo"/>
3
3
  </p>
4
4
 
5
5
  # Mailclerk
@@ -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
+ - [Testing](#testing)
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,16 +51,16 @@ 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
- # config/initializers/mailcerk.rb
55
- Mailclerk.api_key = "mc_yourprivatekey"
54
+ ```ruby
55
+ # config/initializers/mailclerk.rb
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
59
60
  production API keys in environmental variables_.
60
61
 
61
- The default API endpoint is `https://api.mailcerk.app`. To change this, you
62
- can provide a `MAILCLERK_API_URL` ENV variable or set `Mailclerk.mailcerk_url`.
62
+ The default API endpoint is `https://api.mailclerk.app`. To change this, you
63
+ can provide a `MAILCLERK_API_URL` ENV variable or set `Mailclerk.mailclerk_url`.
63
64
 
64
65
  ## Usage
65
66
 
@@ -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
+ ## Testing
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 current 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
- "0.1.1"
29
+ "1.1.1"
26
30
  end
27
31
 
28
32
  def self.version_label
@@ -30,47 +34,19 @@ module Mailclerk
30
34
  end
31
35
  end
32
36
 
33
- class MailclerkError < StandardError
34
- end
35
-
36
- class Client
37
- def initialize(api_key, api_url=nil)
38
- @api_key = api_key
39
- @api_url = api_url || ENV['MAILCLERK_API_URL'] || DEFAULT_API_URL
40
-
41
- if @api_key.nil?
42
- raise MailclerkError.new "No Mailclerk API Key provided. Set `Mailclerk.api_key`"
43
- end
44
-
45
- if @api_url.nil? || @api_url.empty?
46
- raise MailclerkError.new "Mailclerk API URL empty"
47
- end
48
- end
49
-
50
- def deliver(template, recipient, data={}, options={})
51
- conn = Faraday.new(url: @api_url)
52
- conn.basic_auth(@api_key, '')
53
-
54
- resp = conn.post('deliver', {
55
- 'template' => template,
56
- 'recipient' => recipient,
57
- 'data' => data,
58
- 'options' => options
59
- }.to_json, {
60
- 'Content-Type' => 'application/json',
61
- 'X-Client-Version' => Identity.version_label
62
- })
63
-
64
- return resp
65
- end
66
- end
67
-
68
37
  # Syntax intended to emulate ActionMailer
69
38
  def self.deliver(*args)
70
39
  api_key = self.api_key || ENV['MAILCLERK_API_KEY']
71
40
 
72
- client = Client.new(api_key, self.api_url)
41
+ client = Mailclerk::Client.new(api_key, self.api_url)
73
42
  return client.deliver(*args)
74
43
  end
44
+
45
+ def self.outbox
46
+ @outbox ||= Mailclerk::Outbox.new
47
+ end
75
48
 
76
- end
49
+ def self.outbox_enabled?
50
+ !!(@outbox && @outbox.enabled)
51
+ end
52
+ end
data/lib/outbox.rb ADDED
@@ -0,0 +1,91 @@
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
+ self.select do |email|
20
+ query.all? do |key, value|
21
+ email[key] == value
22
+ end
23
+ end
24
+ end
25
+
26
+ def add_send(request, response)
27
+ email = OutboxEmail.new(
28
+ OutboxEmail.recursive_init(
29
+ response.merge(request)
30
+ )
31
+ )
32
+ self << email
33
+ end
34
+ end
35
+
36
+ class OutboxEmail < OpenStruct
37
+
38
+ def self.recursive_init(data)
39
+
40
+ data.each do |key, val|
41
+ if val.is_a?(Hash)
42
+ data[key] = self.recursive_init(val)
43
+ else
44
+ data[key] = val
45
+ end
46
+ end
47
+
48
+ return OpenStruct.new(data)
49
+ end
50
+
51
+ # Custom getters
52
+
53
+ def recipient_email
54
+ return parse_recipient[:address]
55
+ end
56
+
57
+ def recipient_name
58
+ return parse_recipient[:name]
59
+ end
60
+
61
+ private
62
+
63
+ def parse_recipient
64
+ return {} unless self.recipient
65
+
66
+ if self.recipient.is_a?(OpenStruct)
67
+ return self.recipient
68
+ end
69
+
70
+ text = self.recipient.strip
71
+
72
+ if text =~ /^[^<]+<[^<]+>$/
73
+ parts = text.split("<", 2);
74
+
75
+ name = parts[0].strip.gsub('"', "")
76
+
77
+ address = parts[1].strip.gsub(">", "")
78
+
79
+ return {
80
+ name: name,
81
+ address: address
82
+ }
83
+ else
84
+ return {
85
+ name: nil,
86
+ address: text
87
+ }
88
+ end
89
+ end
90
+ end
91
+ 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: 0.1.1
4
+ version: 1.1.1
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-01-28 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
@@ -133,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
150
  requirements:
134
151
  - - "~>"
135
152
  - !ruby/object:Gem::Version
136
- version: '2.7'
153
+ version: '2.5'
137
154
  required_rubygems_version: !ruby/object:Gem::Requirement
138
155
  requirements:
139
156
  - - ">="