idlemailer 1.0.0 → 2.2.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 +5 -5
- data/README.md +93 -13
- data/lib/idlemailer/config.rb +2 -2
- data/lib/idlemailer/defaults.rb +1 -0
- data/lib/idlemailer/html_safe_string.rb +16 -0
- data/lib/idlemailer/mailer.rb +7 -0
- data/lib/idlemailer/message.rb +8 -26
- data/lib/idlemailer/template_manager.rb +68 -0
- data/lib/idlemailer/templates.rb +27 -0
- data/lib/idlemailer/testing.rb +60 -0
- data/lib/idlemailer/version.rb +1 -1
- data/lib/idlemailer.rb +8 -0
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 288e28b5d6f7ac40873806faa8bf56b8e66143a96819be6025238bcbc5fbc239
|
4
|
+
data.tar.gz: 76389af5d9027c264ae2cd2ae0f014a184a3bff41204a001d0a9061ef83e223f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 294f547d16812a33f260ac1dfd10602de80e62cda27c8bf6d4401745c2b8e75c74fd840103f2bb04552df1bc4da4da6878de8a4bd40ad213301171ba6649c8aa
|
7
|
+
data.tar.gz: f86dfb20178f2dbc43826b6ffb1e879009eed952be403be29f41873c2d19d7aa431e2e00b90ae6d1a8ebc58bd2d92a1637c054be7d4fe6f323fdb0443c47a480
|
data/README.md
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
# IdleMailer
|
2
2
|
|
3
|
-
A lightweight (~
|
3
|
+
A lightweight (~200 line) alternative to ActionMailer for Rubyists who are too cool for Rails. Powered by the [mail](http://www.rubydoc.info/gems/mail) gem. Great for API-only backends that need to send email.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
Add to your Gemfile.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'idlemailer'
|
11
|
+
```
|
9
12
|
|
10
13
|
## Use
|
11
14
|
|
12
|
-
IdleMailer
|
15
|
+
IdleMailer provides mailer classes and templates on top of the [mail](http://www.rubydoc.info/gems/mail) gem. `mail` has a great API, so you have unfettered access to it in your mailers.
|
13
16
|
|
14
17
|
```ruby
|
15
18
|
# Define your mailer class
|
@@ -17,18 +20,58 @@ class WidgetMailer
|
|
17
20
|
include IdleMailer::Mailer
|
18
21
|
|
19
22
|
def initialize(user, widget)
|
23
|
+
@widget = widget
|
20
24
|
mail.to = user.email
|
21
25
|
mail.subject = "Widget #{widget.sku}"
|
22
|
-
|
26
|
+
# 'mail' is just a Mail object from the mail gem, so you can use the
|
27
|
+
# full Mail api here, e.g. to, subject, attachments, etc.
|
23
28
|
end
|
24
29
|
end
|
25
30
|
|
26
|
-
# Create widget.html.erb and/or widget.text.erb templates.
|
27
|
-
# They'll have access to instance variables like @widget above.
|
31
|
+
# Create widget.html.erb and/or widget.text.erb in your templates directory.
|
32
|
+
# They'll have access to instance variables like @widget above, as well as any methods you define.
|
28
33
|
|
29
34
|
# Send your mail
|
30
|
-
|
31
|
-
|
35
|
+
WidgetMailer.new(current_user, widget).deliver
|
36
|
+
```
|
37
|
+
|
38
|
+
### HTML escaping
|
39
|
+
|
40
|
+
All values will be automatically HTML-escaped. If you need to bypass escapeing, use the `raw` helper:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
<%= raw @something_with_safe_html %>
|
44
|
+
```
|
45
|
+
|
46
|
+
### Inline templates
|
47
|
+
|
48
|
+
If you prefer, you can embed your ERB templates right inside your Ruby class, instead of making separate template files. Slick amiright?
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
class WidgetMailer
|
52
|
+
include IdleMailer::Mailer
|
53
|
+
|
54
|
+
# optionally override the default layout
|
55
|
+
self.layout = "widget_layout"
|
56
|
+
|
57
|
+
def initialize(user, widget)
|
58
|
+
@widget = widget
|
59
|
+
mail.to = user.email
|
60
|
+
mail.subject = "Widget #{widget.sku}"
|
61
|
+
end
|
62
|
+
|
63
|
+
text %(
|
64
|
+
A new widget called <%= @widget %> was just created!
|
65
|
+
|
66
|
+
Thanks!
|
67
|
+
)
|
68
|
+
|
69
|
+
html %(
|
70
|
+
<p>A new widget called <%= @widget %> was just created!</p>
|
71
|
+
|
72
|
+
<p>Thanks!</p>
|
73
|
+
)
|
74
|
+
end
|
32
75
|
```
|
33
76
|
|
34
77
|
## Configure
|
@@ -40,7 +83,10 @@ IdleMailer.config do |config|
|
|
40
83
|
# Directory containing the mailer templates
|
41
84
|
config.templates = Pathname.new(Dir.getwd).join('templates')
|
42
85
|
|
43
|
-
#
|
86
|
+
# Pre-cache all templates and layouts (instead of re-loading them on each delivery)
|
87
|
+
config.cache_templates = true
|
88
|
+
|
89
|
+
# Name of the default layout template. Here, the file(s) would be named
|
44
90
|
# mailer_layout.html.erb and/or mailer_layout.text.erb.
|
45
91
|
config.layout = 'mailer_layout'
|
46
92
|
|
@@ -73,7 +119,7 @@ end
|
|
73
119
|
|
74
120
|
## Testing
|
75
121
|
|
76
|
-
Put the mailer
|
122
|
+
Put the mailer into testing mode:
|
77
123
|
|
78
124
|
```ruby
|
79
125
|
IdleMailer.config do |config|
|
@@ -81,10 +127,44 @@ IdleMailer.config do |config|
|
|
81
127
|
end
|
82
128
|
```
|
83
129
|
|
84
|
-
Then
|
130
|
+
Then configure your test runner. Here's an example with RSpec:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
RSpec.configure do |config|
|
134
|
+
# Clear sent mail after every test
|
135
|
+
config.after :each do
|
136
|
+
IdleMailer::Testing.clear_mail!
|
137
|
+
end
|
138
|
+
|
139
|
+
# Include the test helpers in your specs
|
140
|
+
config.include IdleMailer::Testing::Helpers
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
Your tests will have access to these helper methods. (Note you can also call them directly on `IdleMailer::Testing` as well)
|
85
145
|
|
86
146
|
```ruby
|
87
|
-
|
147
|
+
# quick boolean checks
|
148
|
+
sent_mail_to? 'user@example.com'
|
149
|
+
sent_mail_to? 'user@example.com', /subject/
|
150
|
+
sent_mail_to? 'user@example.com', /subject/, /body/
|
151
|
+
sent_mail_with_subject? /Foo/
|
152
|
+
sent_mail_with_body? /Bar/
|
153
|
+
sent_mail_from? 'user@example.com'
|
154
|
+
|
155
|
+
# get arrays of matching sent mail (Mail::Message objects)
|
156
|
+
mail_to 'user@example.com'
|
157
|
+
mail_to 'user@example.com', /subject/
|
158
|
+
mail_to 'user@example.com', /subject/, /body/
|
159
|
+
mail_with_subject /Foo/
|
160
|
+
mail_with_body /Bar/
|
161
|
+
mail_from 'user@example.com'
|
162
|
+
|
163
|
+
# get an array of all sent mail
|
164
|
+
sent_mail
|
165
|
+
|
166
|
+
# clear all sent mail
|
167
|
+
clear_mail!
|
88
168
|
```
|
89
169
|
|
90
170
|
## License
|
data/lib/idlemailer/config.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
module IdleMailer
|
2
2
|
# Struct for holding IdleMailer config
|
3
3
|
# templates A Pathname object pointing to the mail templates directory (defaults to ./templates)
|
4
|
-
# layout Name of layout file, minus extention (defaults to mailer_layout)
|
4
|
+
# layout Name of default layout file, minus extention (defaults to mailer_layout)
|
5
5
|
# delivery_method Symbol like :smtp or :test (see the mail gem for all options)
|
6
6
|
# delivery_options Hash of delivery options (see the mail gem for all options)
|
7
7
|
# default_from Default "from" address if it's left blank
|
8
8
|
# logger a Logger object for logging email
|
9
9
|
# log_body if true, the entire message body will be logged (instead of just the headers) (default false)
|
10
|
-
Config = Struct.new(:templates, :layout, :delivery_method, :delivery_options, :default_from, :logger, :log_body)
|
10
|
+
Config = Struct.new(:templates, :layout, :cache_templates, :delivery_method, :delivery_options, :default_from, :logger, :log_body)
|
11
11
|
@config = Config.new
|
12
12
|
|
13
13
|
# Takes a block and hands it an IdleMailer::Config object
|
data/lib/idlemailer/defaults.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
module IdleMailer
|
2
|
+
class HtmlSafeString < String
|
3
|
+
def <<(str)
|
4
|
+
safe_str = str.is_a?(HtmlSafeString) ? str : ERB::Util.html_escape(str.to_s)
|
5
|
+
super safe_str
|
6
|
+
end
|
7
|
+
|
8
|
+
def safe_concat(val)
|
9
|
+
self << HtmlSafeString.new(val)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
self
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/idlemailer/mailer.rb
CHANGED
@@ -4,6 +4,9 @@ module IdleMailer
|
|
4
4
|
# class WidgetMailer
|
5
5
|
# include IdleMailer::Mailer
|
6
6
|
#
|
7
|
+
# # optionally override the default layout
|
8
|
+
# self.layout = "widget_layout"
|
9
|
+
#
|
7
10
|
# def initialize(address, widget)
|
8
11
|
# mail.to = address
|
9
12
|
# mail.subject = "Widget #{widget.sku}"
|
@@ -18,6 +21,10 @@ module IdleMailer
|
|
18
21
|
# mailer.deliver
|
19
22
|
#
|
20
23
|
module Mailer
|
24
|
+
def self.included(klass)
|
25
|
+
klass.extend TemplateManager
|
26
|
+
end
|
27
|
+
|
21
28
|
# Deliver mail
|
22
29
|
def deliver
|
23
30
|
mailer = IdleMailer::Message.new(mail, self)
|
data/lib/idlemailer/message.rb
CHANGED
@@ -13,17 +13,19 @@ module IdleMailer
|
|
13
13
|
|
14
14
|
# Deliver mail
|
15
15
|
def deliver!
|
16
|
-
if has_template? 'html'
|
16
|
+
if mailer.class.has_template? 'html'
|
17
17
|
html_body = layout('html') { body('html') }
|
18
18
|
mail.html_part do
|
19
19
|
content_type 'text/html; charset=UTF-8'
|
20
20
|
body html_body
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
|
+
if mailer.class.has_template? 'text'
|
24
25
|
text_body = layout('text') { body('text') }
|
25
26
|
mail.text_part { body text_body }
|
26
27
|
end
|
28
|
+
|
27
29
|
config = IdleMailer.config
|
28
30
|
mail.from config.default_from if mail.from.nil?
|
29
31
|
mail.delivery_method config.delivery_method, config.delivery_options
|
@@ -35,35 +37,15 @@ module IdleMailer
|
|
35
37
|
private
|
36
38
|
|
37
39
|
def body(type)
|
38
|
-
render
|
40
|
+
render mailer.class.template(type)
|
39
41
|
end
|
40
42
|
|
41
43
|
def layout(type)
|
42
|
-
has_layout?(type) ? render(
|
43
|
-
end
|
44
|
-
|
45
|
-
def render(path)
|
46
|
-
mailer.render(ERB.new(File.read(path))) { yield }
|
47
|
-
end
|
48
|
-
|
49
|
-
def has_template?(type)
|
50
|
-
File.exists? template_path(template_name, type)
|
51
|
-
end
|
52
|
-
|
53
|
-
def has_layout?(type)
|
54
|
-
File.exists? template_path(IdleMailer.config.layout, type)
|
55
|
-
end
|
56
|
-
|
57
|
-
def template_name
|
58
|
-
@name ||= mailer.class.name.
|
59
|
-
gsub(/::/, File::SEPARATOR).
|
60
|
-
sub(/Mailer$/, '').
|
61
|
-
gsub(/([a-z])([A-Z])/, "\\1_\\2").
|
62
|
-
downcase
|
44
|
+
mailer.class.has_layout?(type) ? render(mailer.class.layout(type)) { yield } : yield
|
63
45
|
end
|
64
46
|
|
65
|
-
def
|
66
|
-
|
47
|
+
def render(template)
|
48
|
+
mailer.render(template) { yield }
|
67
49
|
end
|
68
50
|
end
|
69
51
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module IdleMailer
|
2
|
+
# Loads a mailer's templates and layouts
|
3
|
+
module TemplateManager
|
4
|
+
def self.extended(klass)
|
5
|
+
klass.class_eval do
|
6
|
+
include Templates::Helpers
|
7
|
+
class << self
|
8
|
+
attr_reader :layouts, :templates
|
9
|
+
end
|
10
|
+
@custom_layout, @layouts, @templates = nil, {}, {}
|
11
|
+
end
|
12
|
+
klass.cache_templates! if IdleMailer.config.cache_templates
|
13
|
+
end
|
14
|
+
|
15
|
+
def text(str)
|
16
|
+
templates['text'] = Templates.compile str.chomp
|
17
|
+
end
|
18
|
+
|
19
|
+
def html(str)
|
20
|
+
templates['html'] = Templates.compile str.chomp
|
21
|
+
end
|
22
|
+
|
23
|
+
def template(type)
|
24
|
+
templates[type] || Templates.compile(template_path(template_name, type).read.chomp)
|
25
|
+
end
|
26
|
+
|
27
|
+
def layout(type)
|
28
|
+
layouts[type] || Templates.compile(template_path(layout_name, type).read.chomp)
|
29
|
+
end
|
30
|
+
|
31
|
+
def layout=(new_name)
|
32
|
+
@custom_layout = new_name
|
33
|
+
layouts.clear
|
34
|
+
cache_templates! if IdleMailer.config.cache_templates
|
35
|
+
end
|
36
|
+
|
37
|
+
def has_template?(type)
|
38
|
+
templates.has_key?(type) || template_path(template_name, type).exist?
|
39
|
+
end
|
40
|
+
|
41
|
+
def has_layout?(type)
|
42
|
+
layouts.has_key?(type) || template_path(layout_name, type).exist?
|
43
|
+
end
|
44
|
+
|
45
|
+
def template_name
|
46
|
+
@name ||= self.name.
|
47
|
+
gsub(/::/, File::SEPARATOR).
|
48
|
+
sub(/Mailer$/, '').
|
49
|
+
gsub(/([a-z])([A-Z])/, "\\1_\\2").
|
50
|
+
downcase
|
51
|
+
end
|
52
|
+
|
53
|
+
def layout_name
|
54
|
+
@custom_layout || IdleMailer.config.layout
|
55
|
+
end
|
56
|
+
|
57
|
+
def template_path(name, type)
|
58
|
+
IdleMailer.config.templates.join("#{name}.#{type}.erb")
|
59
|
+
end
|
60
|
+
|
61
|
+
def cache_templates!
|
62
|
+
layouts['text'] ||= layout 'text' if has_layout? 'text'
|
63
|
+
layouts['html'] ||= layout 'html' if has_layout? 'html'
|
64
|
+
templates['text'] ||= template 'text' if has_template? 'text'
|
65
|
+
templates['html'] ||= template 'html' if has_template? 'html'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module IdleMailer
|
2
|
+
module Templates
|
3
|
+
def self.compile(src)
|
4
|
+
compiler = ERB::Compiler.new("<>")
|
5
|
+
compiler.pre_cmd = ["_erbout=+HtmlSafeString.new"]
|
6
|
+
compiler.put_cmd = "_erbout.safe_concat"
|
7
|
+
compiler.insert_cmd = "_erbout.<<"
|
8
|
+
compiler.post_cmd = ["_erbout"]
|
9
|
+
code, _enc = compiler.compile(src)
|
10
|
+
Template.new code.freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
Template = Struct.new(:code) do
|
14
|
+
def result(bind)
|
15
|
+
_erbout = HtmlSafeString.new
|
16
|
+
eval code, bind
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Helpers
|
21
|
+
# Don't HTML-escape the given value
|
22
|
+
def raw(str)
|
23
|
+
HtmlSafeString.new(str)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module IdleMailer
|
2
|
+
# Module for testing. You can call all IdleMailer::Testing::Helpers methods directly on this module if you want.
|
3
|
+
module Testing
|
4
|
+
# Helpers for your tests
|
5
|
+
module Helpers
|
6
|
+
# Returns true if any mail was sent from the given email address.
|
7
|
+
def sent_mail_from?(addr)
|
8
|
+
mail_from(addr).any?
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns true if any mail was sent to the given email address. You may pass subject and body patterns to get more specific (String or Regexp).
|
12
|
+
def sent_mail_to?(addr, subject = nil, body = nil)
|
13
|
+
mail_to(addr, subject, body).any?
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns true if any mail was sent matching the given subject (String or Regexp).
|
17
|
+
def sent_mail_with_subject?(pattern)
|
18
|
+
mail_with_subject(pattern).any?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns true if any mail was sent matching the given body (Regexp).
|
22
|
+
def sent_mail_with_body?(pattern)
|
23
|
+
mail_with_body(pattern).any?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns all mail sent from the given email address.
|
27
|
+
def mail_from(addr)
|
28
|
+
sent_mail.select { |m| m.from.include? addr }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns all mail sent to the given email address. You may pass subject and body patterns to get more specific (String or Regexp).
|
32
|
+
def mail_to(addr, subject = nil, body = nil)
|
33
|
+
sent_mail.select { |m|
|
34
|
+
m.to.include?(addr) && (subject.nil? || subject === m.subject) && (body.nil? || body === m.to_s)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns all mail sent matching the given subject (String or Regexp).
|
39
|
+
def mail_with_subject(pattern)
|
40
|
+
sent_mail.select { |m| pattern === m.subject }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns all mail sent matching the given body (Regexp).
|
44
|
+
def mail_with_body(pattern)
|
45
|
+
sent_mail.select { |m| pattern === m.to_s }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns all sent mail.
|
49
|
+
def sent_mail
|
50
|
+
Mail::TestMailer.deliveries
|
51
|
+
end
|
52
|
+
|
53
|
+
# Clears sent mail.
|
54
|
+
def clear_mail!
|
55
|
+
Mail::TestMailer.deliveries.clear
|
56
|
+
end
|
57
|
+
end
|
58
|
+
extend Helpers
|
59
|
+
end
|
60
|
+
end
|
data/lib/idlemailer/version.rb
CHANGED
data/lib/idlemailer.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
require 'erb'
|
2
2
|
require 'pathname'
|
3
3
|
require 'mail'
|
4
|
+
|
4
5
|
require 'idlemailer/config'
|
5
6
|
require 'idlemailer/defaults'
|
6
7
|
require 'idlemailer/message'
|
7
8
|
require 'idlemailer/mailer'
|
9
|
+
require 'idlemailer/template_manager'
|
10
|
+
require 'idlemailer/templates'
|
11
|
+
require 'idlemailer/html_safe_string'
|
8
12
|
require 'idlemailer/version'
|
13
|
+
|
14
|
+
module IdleMailer
|
15
|
+
autoload :Testing, 'idlemailer/testing'
|
16
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: idlemailer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Hollinger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mail
|
@@ -36,8 +36,12 @@ files:
|
|
36
36
|
- lib/idlemailer.rb
|
37
37
|
- lib/idlemailer/config.rb
|
38
38
|
- lib/idlemailer/defaults.rb
|
39
|
+
- lib/idlemailer/html_safe_string.rb
|
39
40
|
- lib/idlemailer/mailer.rb
|
40
41
|
- lib/idlemailer/message.rb
|
42
|
+
- lib/idlemailer/template_manager.rb
|
43
|
+
- lib/idlemailer/templates.rb
|
44
|
+
- lib/idlemailer/testing.rb
|
41
45
|
- lib/idlemailer/version.rb
|
42
46
|
homepage: https://github.com/jhollinger/idlemailer
|
43
47
|
licenses: []
|
@@ -50,17 +54,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
54
|
requirements:
|
51
55
|
- - ">="
|
52
56
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
57
|
+
version: 2.0.0
|
54
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
59
|
requirements:
|
56
60
|
- - ">="
|
57
61
|
- !ruby/object:Gem::Version
|
58
62
|
version: '0'
|
59
63
|
requirements: []
|
60
|
-
|
61
|
-
rubygems_version: 2.4.5.1
|
64
|
+
rubygems_version: 3.0.3
|
62
65
|
signing_key:
|
63
66
|
specification_version: 4
|
64
67
|
summary: A lightweight alternative to ActionMailer
|
65
68
|
test_files: []
|
66
|
-
has_rdoc:
|