courrier 0.9.0 → 0.11.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/Gemfile +1 -1
- data/Gemfile.lock +16 -24
- data/README.md +178 -74
- data/courrier.gemspec +4 -4
- data/lib/courrier/configuration.rb +2 -4
- data/lib/courrier/email/provider.rb +14 -6
- data/lib/courrier/email/providers/base.rb +7 -2
- data/lib/courrier/email/providers/cloudflare.rb +35 -0
- data/lib/courrier/email/providers/lettermint.rb +31 -0
- data/lib/courrier/email/providers/loops.rb +1 -1
- data/lib/courrier/email/providers/mailgun.rb +1 -1
- data/lib/courrier/email/providers/mailjet.rb +1 -1
- data/lib/courrier/email/providers/mailpace.rb +1 -1
- data/lib/courrier/email/providers/postmark.rb +1 -1
- data/lib/courrier/email/providers/resend.rb +1 -1
- data/lib/courrier/email/providers/sendgrid.rb +1 -1
- data/lib/courrier/email/providers/ses.rb +75 -0
- data/lib/courrier/email/providers/smtp2go.rb +29 -0
- data/lib/courrier/email/providers/sparkpost.rb +1 -1
- data/lib/courrier/email/providers/userlist.rb +1 -1
- data/lib/courrier/email/request.rb +1 -1
- data/lib/courrier/email/transformer.rb +9 -9
- data/lib/courrier/email.rb +50 -38
- data/lib/courrier/errors.rb +0 -2
- data/lib/courrier/markdown.rb +52 -0
- data/lib/courrier/test.rb +38 -0
- data/lib/courrier/test_helper.rb +65 -0
- data/lib/courrier/version.rb +1 -1
- data/lib/courrier.rb +2 -2
- metadata +18 -31
- data/app/controllers/courrier/previews/cleanups_controller.rb +0 -13
- data/app/controllers/courrier/previews_controller.rb +0 -23
- data/app/views/courrier/previews/index.html.erb +0 -171
- data/config/routes.rb +0 -8
- data/lib/courrier/configuration/inbox.rb +0 -21
- data/lib/courrier/email/providers/inbox/default.html.erb +0 -126
- data/lib/courrier/email/providers/inbox.rb +0 -83
- data/lib/courrier/engine.rb +0 -7
- data/lib/courrier/jobs/email_delivery_job.rb +0 -23
- data/lib/courrier/railtie.rb +0 -23
- data/lib/courrier/tasks/courrier.rake +0 -13
- data/lib/generators/courrier/email_generator.rb +0 -42
- data/lib/generators/courrier/install_generator.rb +0 -11
- data/lib/generators/courrier/templates/email/password_reset.rb.tt +0 -29
- data/lib/generators/courrier/templates/email/welcome.rb.tt +0 -43
- data/lib/generators/courrier/templates/email.rb.tt +0 -15
- data/lib/generators/courrier/templates/initializer.rb.tt +0 -43
metadata
CHANGED
|
@@ -1,35 +1,34 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: courrier
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rails Designer
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
13
|
+
name: logger
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
16
|
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '1.5'
|
|
20
19
|
- - "<"
|
|
21
20
|
- !ruby/object:Gem::Version
|
|
22
|
-
version: '
|
|
21
|
+
version: '3'
|
|
23
22
|
type: :runtime
|
|
24
23
|
prerelease: false
|
|
25
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
25
|
requirements:
|
|
27
26
|
- - ">="
|
|
28
27
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: '
|
|
28
|
+
version: '1.5'
|
|
30
29
|
- - "<"
|
|
31
30
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '
|
|
31
|
+
version: '3'
|
|
33
32
|
- !ruby/object:Gem::Dependency
|
|
34
33
|
name: nokogiri
|
|
35
34
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -62,17 +61,12 @@ files:
|
|
|
62
61
|
- Gemfile.lock
|
|
63
62
|
- README.md
|
|
64
63
|
- Rakefile
|
|
65
|
-
- app/controllers/courrier/previews/cleanups_controller.rb
|
|
66
|
-
- app/controllers/courrier/previews_controller.rb
|
|
67
|
-
- app/views/courrier/previews/index.html.erb
|
|
68
64
|
- bin/console
|
|
69
65
|
- bin/release
|
|
70
66
|
- bin/setup
|
|
71
|
-
- config/routes.rb
|
|
72
67
|
- courrier.gemspec
|
|
73
68
|
- lib/courrier.rb
|
|
74
69
|
- lib/courrier/configuration.rb
|
|
75
|
-
- lib/courrier/configuration/inbox.rb
|
|
76
70
|
- lib/courrier/configuration/providers.rb
|
|
77
71
|
- lib/courrier/email.rb
|
|
78
72
|
- lib/courrier/email/address.rb
|
|
@@ -80,8 +74,8 @@ files:
|
|
|
80
74
|
- lib/courrier/email/options.rb
|
|
81
75
|
- lib/courrier/email/provider.rb
|
|
82
76
|
- lib/courrier/email/providers/base.rb
|
|
83
|
-
- lib/courrier/email/providers/
|
|
84
|
-
- lib/courrier/email/providers/
|
|
77
|
+
- lib/courrier/email/providers/cloudflare.rb
|
|
78
|
+
- lib/courrier/email/providers/lettermint.rb
|
|
85
79
|
- lib/courrier/email/providers/logger.rb
|
|
86
80
|
- lib/courrier/email/providers/loops.rb
|
|
87
81
|
- lib/courrier/email/providers/mailgun.rb
|
|
@@ -90,15 +84,15 @@ files:
|
|
|
90
84
|
- lib/courrier/email/providers/postmark.rb
|
|
91
85
|
- lib/courrier/email/providers/resend.rb
|
|
92
86
|
- lib/courrier/email/providers/sendgrid.rb
|
|
87
|
+
- lib/courrier/email/providers/ses.rb
|
|
88
|
+
- lib/courrier/email/providers/smtp2go.rb
|
|
93
89
|
- lib/courrier/email/providers/sparkpost.rb
|
|
94
90
|
- lib/courrier/email/providers/userlist.rb
|
|
95
91
|
- lib/courrier/email/request.rb
|
|
96
92
|
- lib/courrier/email/result.rb
|
|
97
93
|
- lib/courrier/email/transformer.rb
|
|
98
|
-
- lib/courrier/engine.rb
|
|
99
94
|
- lib/courrier/errors.rb
|
|
100
|
-
- lib/courrier/
|
|
101
|
-
- lib/courrier/railtie.rb
|
|
95
|
+
- lib/courrier/markdown.rb
|
|
102
96
|
- lib/courrier/subscriber.rb
|
|
103
97
|
- lib/courrier/subscriber/base.rb
|
|
104
98
|
- lib/courrier/subscriber/beehiiv.rb
|
|
@@ -108,21 +102,15 @@ files:
|
|
|
108
102
|
- lib/courrier/subscriber/mailchimp.rb
|
|
109
103
|
- lib/courrier/subscriber/mailerlite.rb
|
|
110
104
|
- lib/courrier/subscriber/result.rb
|
|
111
|
-
- lib/courrier/
|
|
105
|
+
- lib/courrier/test.rb
|
|
106
|
+
- lib/courrier/test_helper.rb
|
|
112
107
|
- lib/courrier/version.rb
|
|
113
|
-
|
|
114
|
-
- lib/generators/courrier/install_generator.rb
|
|
115
|
-
- lib/generators/courrier/templates/email.rb.tt
|
|
116
|
-
- lib/generators/courrier/templates/email/password_reset.rb.tt
|
|
117
|
-
- lib/generators/courrier/templates/email/welcome.rb.tt
|
|
118
|
-
- lib/generators/courrier/templates/initializer.rb.tt
|
|
119
|
-
homepage: https://railsdesigner.com/courrier/
|
|
108
|
+
homepage: https://railsdesigner.com/open-source/courrier/
|
|
120
109
|
licenses:
|
|
121
110
|
- MIT
|
|
122
111
|
metadata:
|
|
123
|
-
homepage_uri: https://railsdesigner.com/courrier/
|
|
112
|
+
homepage_uri: https://railsdesigner.com/open-source/courrier/
|
|
124
113
|
source_code_uri: https://github.com/Rails-Designer/courrier/
|
|
125
|
-
post_install_message:
|
|
126
114
|
rdoc_options: []
|
|
127
115
|
require_paths:
|
|
128
116
|
- lib
|
|
@@ -130,15 +118,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
130
118
|
requirements:
|
|
131
119
|
- - ">="
|
|
132
120
|
- !ruby/object:Gem::Version
|
|
133
|
-
version:
|
|
121
|
+
version: 4.0.0
|
|
134
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
123
|
requirements:
|
|
136
124
|
- - ">="
|
|
137
125
|
- !ruby/object:Gem::Version
|
|
138
126
|
version: '0'
|
|
139
127
|
requirements: []
|
|
140
|
-
rubygems_version:
|
|
141
|
-
signing_key:
|
|
128
|
+
rubygems_version: 4.0.3
|
|
142
129
|
specification_version: 4
|
|
143
130
|
summary: API-powered email delivery for Ruby apps
|
|
144
131
|
test_files: []
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Courrier
|
|
4
|
-
class PreviewsController < ActionController::Base
|
|
5
|
-
def index
|
|
6
|
-
@emails = emails.map { Courrier::Email::Providers::Inbox::Email.from_file(_1) }
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def show
|
|
10
|
-
file_path = File.join(Courrier.configuration.inbox.destination, params[:id])
|
|
11
|
-
content = File.read(file_path)
|
|
12
|
-
|
|
13
|
-
render html: content.html_safe, layout: false
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
def emails
|
|
19
|
-
@emails ||= Dir.glob("#{Courrier.configuration.inbox.destination}/*.html")
|
|
20
|
-
.sort_by { -File.basename(_1, ".html").to_i }
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>Courrier Inbox</title>
|
|
6
|
-
|
|
7
|
-
<style>
|
|
8
|
-
*, *::before, *::after { box-sizing: border-box; }
|
|
9
|
-
* { margin: 0; padding: 0; }
|
|
10
|
-
body { margin: 0; padding: 0; font-size: 16px; line-height: 1.5; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; background-color: rgb(241, 245, 249); }
|
|
11
|
-
|
|
12
|
-
.sidebar {
|
|
13
|
-
display: flex;
|
|
14
|
-
flex-direction: column;
|
|
15
|
-
position: sticky;
|
|
16
|
-
top: 0;
|
|
17
|
-
padding: .5rem;
|
|
18
|
-
width: min(350px, 33.3333%); height: 100dvh;
|
|
19
|
-
border-right: 1px solid rgb(226, 232, 240);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.sidebar__options {
|
|
23
|
-
position: sticky;
|
|
24
|
-
bottom: 0;
|
|
25
|
-
padding: .5rem;
|
|
26
|
-
background-color: rgb(241, 245, 249);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.sidebar__btn-clear {
|
|
30
|
-
border: none;
|
|
31
|
-
display: flex;
|
|
32
|
-
align-items: center;
|
|
33
|
-
justify-content: center;
|
|
34
|
-
column-gap: 0.25rem;
|
|
35
|
-
width: 100%;
|
|
36
|
-
padding: .5rem;
|
|
37
|
-
font-size: .875rem; line-height: 1.25rem;
|
|
38
|
-
font-weight: 500;
|
|
39
|
-
color: rgb(71, 85, 105);
|
|
40
|
-
background-color: rgb(226, 232, 240);
|
|
41
|
-
border-radius: .5rem;
|
|
42
|
-
cursor: default;
|
|
43
|
-
|
|
44
|
-
&:hover { background-color: rgb(203, 213, 225); }
|
|
45
|
-
&:active { transform: scale(.98); }
|
|
46
|
-
|
|
47
|
-
[data-slot="icon"] {
|
|
48
|
-
width: .875rem; height: .875rem;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.email-previews {
|
|
53
|
-
display: flex;
|
|
54
|
-
flex-direction: column;
|
|
55
|
-
flex: 1;
|
|
56
|
-
row-gap: .5rem;
|
|
57
|
-
overflow-y: auto;
|
|
58
|
-
width: 100%;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.email-preview {
|
|
62
|
-
display: flex;
|
|
63
|
-
flex-direction: row;
|
|
64
|
-
column-gap: .5rem;
|
|
65
|
-
width: 100%;
|
|
66
|
-
padding: .5rem .75rem;
|
|
67
|
-
text-decoration: none;
|
|
68
|
-
border-radius: .5rem;
|
|
69
|
-
|
|
70
|
-
&:hover {
|
|
71
|
-
background-color: rgba(226, 232, 240, .75);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.email-preview--empty {
|
|
76
|
-
display: none;
|
|
77
|
-
text-align: center;
|
|
78
|
-
|
|
79
|
-
&:only-child {
|
|
80
|
-
display: block;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.email-preview__avatar {
|
|
85
|
-
flex-shrink: 0;
|
|
86
|
-
padding: .25rem;
|
|
87
|
-
width: 1.5rem; height: 1.5rem;
|
|
88
|
-
background-color: rgb(203, 213, 225);
|
|
89
|
-
color: rgb(51, 65, 85);
|
|
90
|
-
border-radius: 9999px;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.email-preview__content {
|
|
94
|
-
font-size: 0.875rem; line-height: 1.25rem;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.email-preview__recipient {
|
|
98
|
-
font-size: 1rem; line-height: 1.5rem;
|
|
99
|
-
font-weight: 600;
|
|
100
|
-
letter-spacing: -.025em;
|
|
101
|
-
color: rgb(51, 65, 85);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.email-preview__subject {
|
|
105
|
-
margin-top: .125rem;
|
|
106
|
-
overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;
|
|
107
|
-
color: rgb(100, 116, 139);
|
|
108
|
-
}
|
|
109
|
-
</style>
|
|
110
|
-
</head>
|
|
111
|
-
<body>
|
|
112
|
-
<div style="display: flex; column-gap: 1rem;">
|
|
113
|
-
<aside class="sidebar">
|
|
114
|
-
<ul class="email-previews">
|
|
115
|
-
<li class="email-preview--empty">
|
|
116
|
-
<p class="email-preview__subject">
|
|
117
|
-
No emails yet…
|
|
118
|
-
</p>
|
|
119
|
-
</li>
|
|
120
|
-
|
|
121
|
-
<% @emails.each do |email| %>
|
|
122
|
-
<li>
|
|
123
|
-
<%= link_to courrier.preview_path(email.filename), data: {remote: true}, class: "email-preview" do %>
|
|
124
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon" class="email-preview__avatar">
|
|
125
|
-
<path fill-rule="evenodd" d="M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z" clip-rule="evenodd"/>
|
|
126
|
-
</svg>
|
|
127
|
-
|
|
128
|
-
<div class="email-preview__content">
|
|
129
|
-
<small class="email-preview__recipient">
|
|
130
|
-
<%= email.metadata.to %>
|
|
131
|
-
</small>
|
|
132
|
-
|
|
133
|
-
<p class="email-preview__subject">
|
|
134
|
-
<%= email.metadata.subject || "No subject" %>
|
|
135
|
-
</p>
|
|
136
|
-
</div>
|
|
137
|
-
<% end %>
|
|
138
|
-
</li>
|
|
139
|
-
<% end %>
|
|
140
|
-
</ul>
|
|
141
|
-
|
|
142
|
-
<div class="sidebar__options">
|
|
143
|
-
<%= button_to courrier.cleanup_path, class: "sidebar__btn-clear" do %>
|
|
144
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
|
|
145
|
-
<path fill-rule="evenodd" d="M16.5 4.478v.227a48.816 48.816 0 0 1 3.878.512.75.75 0 1 1-.256 1.478l-.209-.035-1.005 13.07a3 3 0 0 1-2.991 2.77H8.084a3 3 0 0 1-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 0 1-.256-1.478A48.567 48.567 0 0 1 7.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 0 1 3.369 0c1.603.051 2.815 1.387 2.815 2.951Zm-6.136-1.452a51.196 51.196 0 0 1 3.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 0 0-6 0v-.113c0-.794.609-1.428 1.364-1.452Zm-.355 5.945a.75.75 0 1 0-1.5.058l.347 9a.75.75 0 1 0 1.499-.058l-.346-9Zm5.48.058a.75.75 0 1 0-1.498-.058l-.347 9a.75.75 0 0 0 1.5.058l.345-9Z" clip-rule="evenodd"/>
|
|
146
|
-
</svg>
|
|
147
|
-
|
|
148
|
-
Clear inbox
|
|
149
|
-
<% end %>
|
|
150
|
-
</div>
|
|
151
|
-
</aside>
|
|
152
|
-
|
|
153
|
-
<article style="flex: 1;" id="email-preview">
|
|
154
|
-
</article>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
<script>
|
|
158
|
-
document.querySelectorAll("a[data-remote]").forEach(link => {
|
|
159
|
-
link.addEventListener("click", (event) => {
|
|
160
|
-
event.preventDefault();
|
|
161
|
-
|
|
162
|
-
fetch(link.href)
|
|
163
|
-
.then(response => response.text())
|
|
164
|
-
.then(html => {
|
|
165
|
-
document.getElementById("email-preview").innerHTML = html;
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
</script>
|
|
170
|
-
</body>
|
|
171
|
-
</html>
|
data/config/routes.rb
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Courrier
|
|
4
|
-
class Configuration
|
|
5
|
-
class Inbox
|
|
6
|
-
attr_accessor :destination, :auto_open, :template_path
|
|
7
|
-
|
|
8
|
-
def initialize
|
|
9
|
-
@destination = default_destination
|
|
10
|
-
@auto_open = false
|
|
11
|
-
@template_path = File.expand_path("../../../courrier/email/providers/inbox/default.html.erb", __FILE__)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
def default_destination
|
|
17
|
-
defined?(Rails) ? Rails.root.join("tmp", "courrier", "emails").to_s : File.join(Dir.tmpdir, "courrier", "emails")
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
{
|
|
3
|
-
"to": "<%= email %>",
|
|
4
|
-
"subject": "<%= @options.subject %>"
|
|
5
|
-
}
|
|
6
|
-
-->
|
|
7
|
-
|
|
8
|
-
<!DOCTYPE html>
|
|
9
|
-
<html>
|
|
10
|
-
<head>
|
|
11
|
-
<meta charset="UTF-8">
|
|
12
|
-
<title><%= @options.subject %></title>
|
|
13
|
-
<style>
|
|
14
|
-
*, *::before, *::after { box-sizing: border-box; }
|
|
15
|
-
* { margin: 0; padding: 0; }
|
|
16
|
-
body { margin: 0; padding: 0; line-height: 1.5; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; background-color: rgb(241, 245, 249); }
|
|
17
|
-
pre { margin: 0; white-space: pre-wrap; }
|
|
18
|
-
.email {
|
|
19
|
-
width: 100%;
|
|
20
|
-
max-width: 65rem;
|
|
21
|
-
margin-left: auto; margin-right: auto;
|
|
22
|
-
background-color: #fff;
|
|
23
|
-
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
24
|
-
border-bottom-right-radius: 1rem; border-bottom-left-radius: 1rem;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.email__header { display: flex; align-items: center; padding: .75rem; -moz-column-gap: .75rem; column-gap: .75rem; }
|
|
28
|
-
|
|
29
|
-
.email__avatar {
|
|
30
|
-
flex-shrink: 0;
|
|
31
|
-
padding: .25rem;
|
|
32
|
-
width: 2rem; height: 2rem;
|
|
33
|
-
background-color: rgb(203, 213, 225);
|
|
34
|
-
color: rgb(51, 65, 85);
|
|
35
|
-
border-radius: 9999px;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.email__recipient { flex-grow: 1; font-size: .875rem; line-height: 1.25rem; }
|
|
39
|
-
|
|
40
|
-
.email__recipient-name { font-weight: 600; color: rgb(51, 65, 85); }
|
|
41
|
-
|
|
42
|
-
.email__metadata { display: flex; align-items: center; justify-content: space-between; }
|
|
43
|
-
|
|
44
|
-
.email__recipient-email { color: rgb(100, 116, 139); }
|
|
45
|
-
|
|
46
|
-
.email__datetime { font-size: .75rem; line-height: 1rem; color: rgb(148, 163, 184); }
|
|
47
|
-
|
|
48
|
-
.email__subject {
|
|
49
|
-
margin-left: 3.5rem;
|
|
50
|
-
font-size: 1.25rem; line-height: 1.75rem;
|
|
51
|
-
font-weight: 700;
|
|
52
|
-
letter-spacing: -.025em;
|
|
53
|
-
color: rgb(30, 41, 59)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.email__preview { margin-top: .75rem; margin-left: 3.5rem; padding-bottom: 1rem; }
|
|
57
|
-
|
|
58
|
-
.preview-toggle { display: none; }
|
|
59
|
-
.preview-toggle-label {
|
|
60
|
-
display: inline-block;
|
|
61
|
-
padding: .25rem .875rem;
|
|
62
|
-
font-size: .75rem; line-height: 1rem;
|
|
63
|
-
font-weight: 600;
|
|
64
|
-
color: rgb(30, 41, 59);
|
|
65
|
-
background-color: rgb(255, 255, 255);
|
|
66
|
-
border: 1px solid rgb(226, 232, 240);
|
|
67
|
-
border-radius: .375rem;
|
|
68
|
-
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
69
|
-
cursor: pointer;
|
|
70
|
-
|
|
71
|
-
&:hover { border-color: rgb(203, 213, 225); }
|
|
72
|
-
&:active { transform: scale(.98); }
|
|
73
|
-
}
|
|
74
|
-
.preview-toggle[disabled] + .preview-toggle-label { opacity: 0.5; cursor: not-allowed; }
|
|
75
|
-
|
|
76
|
-
.email__preview-html, .email__preview-text { margin-top: 1.5rem;}
|
|
77
|
-
.email__preview-html { display: none; }
|
|
78
|
-
.preview-toggle:checked ~ .email__preview-text { display: none; }
|
|
79
|
-
.preview-toggle:checked ~ .email__preview-html { display: block; }
|
|
80
|
-
</style>
|
|
81
|
-
</head>
|
|
82
|
-
<body>
|
|
83
|
-
<article class="email">
|
|
84
|
-
<header class="email__header">
|
|
85
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon" class="email__avatar">
|
|
86
|
-
<path fill-rule="evenodd" d="M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z" clip-rule="evenodd"/>
|
|
87
|
-
</svg>
|
|
88
|
-
|
|
89
|
-
<div class="email__recipient">
|
|
90
|
-
<% if name %>
|
|
91
|
-
<p class="email__recipient-name">
|
|
92
|
-
<%= name %>
|
|
93
|
-
</p>
|
|
94
|
-
<% end %>
|
|
95
|
-
|
|
96
|
-
<div class="email__metadata">
|
|
97
|
-
<p class="email__recipient-email">
|
|
98
|
-
<%= email %>
|
|
99
|
-
</p>
|
|
100
|
-
|
|
101
|
-
<time class="email__datetime" datetime="#{Time.now.strftime("%Y-%m-%d %H:%M:%S %z")}">
|
|
102
|
-
<%= Time.now.strftime("%Y-%m-%d %H:%M:%S %z") %>
|
|
103
|
-
</time>
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
|
-
</header>
|
|
107
|
-
|
|
108
|
-
<p class="email__subject">
|
|
109
|
-
<%= @options.subject %>
|
|
110
|
-
</p>
|
|
111
|
-
|
|
112
|
-
<div class="email__preview">
|
|
113
|
-
<input type="checkbox" id="preview-toggle" class="preview-toggle" <%= html ? "" : "disabled" %>>
|
|
114
|
-
<label for="preview-toggle" class="preview-toggle-label">Toggle HTML/Text</label>
|
|
115
|
-
|
|
116
|
-
<div class="email__preview-text">
|
|
117
|
-
<pre><%= text || "(no text content)" %></pre>
|
|
118
|
-
</div>
|
|
119
|
-
|
|
120
|
-
<div class="email__preview-html">
|
|
121
|
-
<%= html || "<p>(no HTML content)</p>" %>
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
</article>
|
|
125
|
-
</body>
|
|
126
|
-
</html>
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "tmpdir"
|
|
4
|
-
require "fileutils"
|
|
5
|
-
require "launchy"
|
|
6
|
-
|
|
7
|
-
module Courrier
|
|
8
|
-
class Email
|
|
9
|
-
module Providers
|
|
10
|
-
class Inbox < Base
|
|
11
|
-
def deliver
|
|
12
|
-
FileUtils.mkdir_p(config.destination)
|
|
13
|
-
|
|
14
|
-
file_path = File.join(config.destination, "#{Time.now.to_i}.html")
|
|
15
|
-
|
|
16
|
-
File.write(file_path, ERB.new(File.read(config.template_path)).result(binding))
|
|
17
|
-
|
|
18
|
-
Launchy.open(file_path) if config.auto_open
|
|
19
|
-
|
|
20
|
-
"📮 Email saved to #{file_path} and #{email_destination}"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def name = extract(@options.to)[:name]
|
|
24
|
-
|
|
25
|
-
def email = extract(@options.to)[:email]
|
|
26
|
-
|
|
27
|
-
def text = prepare(@options.text)
|
|
28
|
-
|
|
29
|
-
def html = prepare(@options.html)
|
|
30
|
-
|
|
31
|
-
private
|
|
32
|
-
|
|
33
|
-
def extract(to)
|
|
34
|
-
if to.to_s =~ /(.*?)\s*<(.+?)>/
|
|
35
|
-
{name: $1.strip, email: $2.strip}
|
|
36
|
-
else
|
|
37
|
-
{name: nil, email: to.to_s.strip}
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def prepare(content)
|
|
42
|
-
content.to_s.gsub(URL_PARSER.make_regexp(%w[http https])) do |url|
|
|
43
|
-
%(<a href="#{url}">#{url}</a>)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def config = @config ||= Courrier.configuration.inbox
|
|
48
|
-
|
|
49
|
-
def email_destination
|
|
50
|
-
return "opened in your default browser" if config.auto_open
|
|
51
|
-
|
|
52
|
-
path = begin
|
|
53
|
-
Rails.application.routes.url_helpers.courrier_path
|
|
54
|
-
rescue
|
|
55
|
-
"/courrier/ (Note: Add `mount Courrier::Engine => \"/courrier\"` to your routes.rb to enable proper routing)"
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
"available at #{path}"
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
URL_PARSER = (
|
|
62
|
-
defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
class Email < Data.define(:path, :filename, :metadata)
|
|
66
|
-
Metadata = Data.define(:to, :subject)
|
|
67
|
-
|
|
68
|
-
def self.from_file(path)
|
|
69
|
-
content = File.read(path)
|
|
70
|
-
json = content[/<!--\s*(.*?)\s*-->/m, 1]
|
|
71
|
-
metadata = JSON.parse(json, symbolize_names: true)
|
|
72
|
-
|
|
73
|
-
new(
|
|
74
|
-
path: path,
|
|
75
|
-
filename: File.basename(path),
|
|
76
|
-
metadata: Metadata.new(**metadata)
|
|
77
|
-
)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|
data/lib/courrier/engine.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Courrier
|
|
4
|
-
module Jobs
|
|
5
|
-
class EmailDeliveryJob < ActiveJob::Base
|
|
6
|
-
def perform(data)
|
|
7
|
-
email_class = data[:email_class].constantize
|
|
8
|
-
|
|
9
|
-
email_class.new(
|
|
10
|
-
provider: data[:provider],
|
|
11
|
-
api_key: data[:api_key],
|
|
12
|
-
from: data[:options][:from],
|
|
13
|
-
to: data[:options][:to],
|
|
14
|
-
reply_to: data[:options][:reply_to],
|
|
15
|
-
cc: data[:options][:cc],
|
|
16
|
-
bcc: data[:options][:bcc],
|
|
17
|
-
provider_options: data[:provider_options],
|
|
18
|
-
context_options: data[:context_options]
|
|
19
|
-
).deliver_now
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
data/lib/courrier/railtie.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
module Courrier
|
|
2
|
-
class Railtie < Rails::Railtie
|
|
3
|
-
config.after_initialize do
|
|
4
|
-
Courrier::Email.default_url_options = Courrier.configuration.default_url_options
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
ActiveSupport.on_load(:action_view) do
|
|
8
|
-
include Courrier::Email::Address
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
ActiveSupport.on_load(:action_controller) do
|
|
12
|
-
include Courrier::Email::Address
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
ActiveSupport.on_load(:active_job) do
|
|
16
|
-
include Courrier::Email::Address
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
rake_tasks do
|
|
20
|
-
load File.expand_path("../tasks/courrier.rake", __FILE__)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
namespace :tmp do
|
|
2
|
-
task :courrier do
|
|
3
|
-
rm_rf Dir["#{Courrier.configuration.inbox.destination}/[^.]*"], verbose: false
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
task clear: :courrier
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
namespace :courrier do
|
|
10
|
-
desc "Clear email files from `#{Courrier.configuration.inbox.destination}`"
|
|
11
|
-
|
|
12
|
-
task clear: "tmp:courrier"
|
|
13
|
-
end
|