letter_opener 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +16 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.rdoc +3 -3
- data/lib/letter_opener/delivery_method.rb +6 -4
- data/lib/letter_opener/message.html.erb +30 -18
- data/lib/letter_opener/message.rb +18 -1
- data/spec/letter_opener/delivery_method_spec.rb +147 -36
- data/spec/letter_opener/message_spec.rb +29 -0
- data/spec/spec_helper.rb +3 -1
- metadata +28 -12
data/CHANGELOG.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
## 0.1.0 ##
|
2
|
+
|
3
|
+
* From and To show name and Email when specified
|
4
|
+
* Fix bug when letter_opener couldn't open email in Windows
|
5
|
+
* Handle spaces in the application path (thanks Mike Boone)
|
6
|
+
* As letter_opener doesn't work with Launchy < 2.0.4 let's depend on >= 2.0.4 (thanks Samnang Chhun)
|
7
|
+
* Handle `reply_to` field (thanks Wes Gibbs)
|
8
|
+
* Set the charset in email preview (thanks Bruno Michel)
|
9
|
+
|
10
|
+
## 0.0.2 ##
|
11
|
+
|
12
|
+
* Fixing launchy requirement (thanks Bruno Michel)
|
13
|
+
|
14
|
+
## 0.0.1 ##
|
15
|
+
|
16
|
+
* Initial relase
|
data/Gemfile
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Ryan Bates
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Letter Opener
|
1
|
+
= Letter Opener {<img src="https://secure.travis-ci.org/ryanb/letter_opener.png" />}[http://travis-ci.org/ryanb/letter_opener]
|
2
2
|
|
3
3
|
Preview email in the browser instead of sending it. This means you do not need to set up email delivery in your development environment, and you no longer need to worry about accidentally sending a test email to someone else's address.
|
4
4
|
|
@@ -28,6 +28,6 @@ If you aren't using Rails, this can be easily set up with the Mail gem. Just set
|
|
28
28
|
|
29
29
|
== Development & Feedback
|
30
30
|
|
31
|
-
Questions or
|
31
|
+
Questions or problems? Please use the {issue tracker}[https://github.com/ryanb/letter_opener/issues]. If you would like to contribute to this project, fork this repository and run +bundle+ and +rake+ to run the tests. Pull requests appreciated.
|
32
32
|
|
33
|
-
Special thanks to the {mail_view}[https://github.com/37signals/mail_view/] gem for inspiring this project and for their mail template.
|
33
|
+
Special thanks to the {mail_view}[https://github.com/37signals/mail_view/] gem for inspiring this project and for their mail template. Also thanks to [Vasiliy Ermolovich](https://github.com/nashby) for helping manage this project.
|
@@ -1,15 +1,17 @@
|
|
1
1
|
module LetterOpener
|
2
2
|
class DeliveryMethod
|
3
3
|
def initialize(options = {})
|
4
|
-
|
4
|
+
self.settings = {:location => './letter_opener'}.merge!(options)
|
5
5
|
end
|
6
6
|
|
7
|
+
attr_accessor :settings
|
8
|
+
|
7
9
|
def deliver!(mail)
|
8
|
-
location = File.join(
|
10
|
+
location = File.join(settings[:location], "#{Time.now.to_i}_#{Digest::SHA1.hexdigest(mail.encoded)[0..6]}")
|
9
11
|
messages = mail.parts.map { |part| Message.new(location, mail, part) }
|
10
12
|
messages << Message.new(location, mail) if messages.empty?
|
11
|
-
messages.each
|
12
|
-
Launchy.open(
|
13
|
+
messages.each(&:render)
|
14
|
+
Launchy.open(URI.parse(URI.escape(messages.first.filepath)))
|
13
15
|
end
|
14
16
|
end
|
15
17
|
end
|
@@ -1,26 +1,25 @@
|
|
1
|
+
<meta http-equiv="Content-Type" content="text/html; charset=<%= encoding %>">
|
2
|
+
|
1
3
|
<style type="text/css">
|
2
4
|
#message_headers {
|
3
|
-
position: absolute;
|
4
|
-
top: 0px;
|
5
|
-
left: 0;
|
6
5
|
width: 100%;
|
7
|
-
height: 85px;
|
8
6
|
padding: 10px 0 0 0;
|
9
7
|
margin: 0;
|
10
8
|
background: #fff;
|
11
9
|
font-size: 12px;
|
12
10
|
font-family: "Lucida Grande";
|
13
11
|
border-bottom: 1px solid #dedede;
|
14
|
-
overflow:
|
12
|
+
overflow: auto;
|
15
13
|
}
|
16
14
|
|
17
15
|
#message_headers dl {
|
18
|
-
|
16
|
+
float: left;
|
17
|
+
margin: 0 0 10px 0;
|
19
18
|
padding: 0;
|
20
19
|
}
|
21
20
|
|
22
21
|
#message_headers dt {
|
23
|
-
width:
|
22
|
+
width: 62px;
|
24
23
|
padding: 1px;
|
25
24
|
float: left;
|
26
25
|
text-align: right;
|
@@ -29,14 +28,13 @@
|
|
29
28
|
}
|
30
29
|
|
31
30
|
#message_headers dd {
|
32
|
-
margin-left:
|
31
|
+
margin-left: 72px;
|
33
32
|
padding: 1px;
|
34
33
|
}
|
35
34
|
|
36
35
|
#message_headers p.alternate {
|
37
|
-
|
38
|
-
|
39
|
-
right: 15px;
|
36
|
+
float: right;
|
37
|
+
margin: 0;
|
40
38
|
}
|
41
39
|
|
42
40
|
#message_headers p.alternate a {
|
@@ -47,16 +45,17 @@
|
|
47
45
|
padding: 10px;
|
48
46
|
word-wrap: break-word;
|
49
47
|
}
|
50
|
-
|
51
|
-
body {
|
52
|
-
margin-top: 96px;
|
53
|
-
}
|
54
48
|
</style>
|
55
49
|
|
56
50
|
<div id="message_headers">
|
57
51
|
<dl>
|
58
52
|
<dt>From:</dt>
|
59
|
-
<dd><%=
|
53
|
+
<dd><%= from %></dd>
|
54
|
+
|
55
|
+
<% unless reply_to.empty? %>
|
56
|
+
<dt>Reply-To:</dt>
|
57
|
+
<dd><%= reply_to %></dd>
|
58
|
+
<% end %>
|
60
59
|
|
61
60
|
<dt>Subject:</dt>
|
62
61
|
<dd><strong><%= mail.subject %></strong></dd>
|
@@ -64,8 +63,20 @@
|
|
64
63
|
<dt>Date:</dt>
|
65
64
|
<dd><%= Time.now.strftime("%b %e, %Y %I:%M:%S %p %Z") %></dd>
|
66
65
|
|
67
|
-
|
68
|
-
|
66
|
+
<% unless to.empty? %>
|
67
|
+
<dt>To:</dt>
|
68
|
+
<dd><%= to %></dd>
|
69
|
+
<% end %>
|
70
|
+
|
71
|
+
<% if mail.cc %>
|
72
|
+
<dt>CC:</dt>
|
73
|
+
<dd><%= mail.cc.join(", ") %></dd>
|
74
|
+
<% end %>
|
75
|
+
|
76
|
+
<% if mail.bcc %>
|
77
|
+
<dt>BCC:</dt>
|
78
|
+
<dd><%= mail.bcc.join(", ") %></dd>
|
79
|
+
<% end %>
|
69
80
|
</dl>
|
70
81
|
|
71
82
|
<% if mail.multipart? %>
|
@@ -84,3 +95,4 @@
|
|
84
95
|
<% else %>
|
85
96
|
<%= body %>
|
86
97
|
<% end %>
|
98
|
+
|
@@ -28,11 +28,28 @@ module LetterOpener
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def body
|
31
|
-
(@part && @part.body || @mail.body).to_s
|
31
|
+
@body ||= (@part && @part.body || @mail.body).to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def from
|
35
|
+
@from ||= Array(@mail.from).join(", ")
|
36
|
+
end
|
37
|
+
|
38
|
+
def to
|
39
|
+
@to ||= Array(@mail.to).join(", ")
|
40
|
+
end
|
41
|
+
|
42
|
+
def reply_to
|
43
|
+
@reply_to ||= Array(@mail.reply_to).join(", ")
|
32
44
|
end
|
33
45
|
|
34
46
|
def type
|
35
47
|
content_type =~ /html/ ? "rich" : "plain"
|
36
48
|
end
|
49
|
+
|
50
|
+
def encoding
|
51
|
+
body.respond_to?(:encoding) ? body.encoding : "utf-8"
|
52
|
+
end
|
37
53
|
end
|
38
54
|
end
|
55
|
+
|
@@ -1,49 +1,160 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe LetterOpener::DeliveryMethod do
|
4
|
-
|
4
|
+
let(:location) { File.expand_path('../../../tmp/letter_opener', __FILE__) }
|
5
|
+
|
6
|
+
before do
|
5
7
|
Launchy.stub(:open)
|
6
|
-
location = File.expand_path('../../../tmp/letter_opener', __FILE__)
|
7
8
|
FileUtils.rm_rf(location)
|
9
|
+
context = self
|
10
|
+
|
8
11
|
Mail.defaults do
|
9
|
-
delivery_method LetterOpener::DeliveryMethod, :location => location
|
12
|
+
delivery_method LetterOpener::DeliveryMethod, :location => context.location
|
10
13
|
end
|
11
|
-
@location = location
|
12
14
|
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
context 'content' do
|
17
|
+
let(:plain_file) { Dir["#{location}/*/plain.html"].first }
|
18
|
+
let(:plain) { File.read(plain_file) }
|
19
|
+
|
20
|
+
context 'plain' do
|
21
|
+
before do
|
22
|
+
Launchy.should_receive(:open)
|
23
|
+
|
24
|
+
Mail.deliver do
|
25
|
+
from 'Foo foo@example.com'
|
26
|
+
reply_to 'No Reply no-reply@example.com'
|
27
|
+
to 'Bar bar@example.com'
|
28
|
+
subject 'Hello'
|
29
|
+
body 'World!'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'creates plain html document' do
|
34
|
+
File.exist?(plain_file).should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'saves From field' do
|
38
|
+
plain.should include("Foo foo@example.com")
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'saves Reply-to field' do
|
42
|
+
plain.should include("No Reply no-reply@example.com")
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'saves To field' do
|
46
|
+
plain.should include("Bar bar@example.com")
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'saves Subject field' do
|
50
|
+
plain.should include("Hello")
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'saves Body field' do
|
54
|
+
plain.should include("World!")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'multipart' do
|
59
|
+
let(:rich_file) { Dir["#{location}/*/rich.html"].first }
|
60
|
+
let(:rich) { File.read(rich_file) }
|
61
|
+
|
62
|
+
before do
|
63
|
+
Launchy.should_receive(:open)
|
64
|
+
|
65
|
+
Mail.deliver do
|
66
|
+
from 'foo@example.com'
|
67
|
+
to 'bar@example.com'
|
68
|
+
subject 'Many parts'
|
69
|
+
text_part do
|
70
|
+
body 'This is <plain> text'
|
71
|
+
end
|
72
|
+
html_part do
|
73
|
+
content_type 'text/html; charset=UTF-8'
|
74
|
+
body '<h1>This is HTML</h1>'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'creates plain html document' do
|
80
|
+
File.exist?(plain_file).should be_true
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'creates rich html document' do
|
84
|
+
File.exist?(rich_file).should be_true
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'shows link to rich html version' do
|
88
|
+
plain.should include("View HTML version")
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'saves text part' do
|
92
|
+
plain.should include("This is <plain> text")
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'saves html part' do
|
96
|
+
rich.should include("<h1>This is HTML</h1>")
|
97
|
+
end
|
98
|
+
end
|
27
99
|
end
|
28
100
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
html
|
46
|
-
|
47
|
-
|
101
|
+
context 'document with spaces in name' do
|
102
|
+
let(:location) { File.expand_path('../../../tmp/letter_opener with space', __FILE__) }
|
103
|
+
let(:file) { Dir["#{location}/*/plain.html"].first }
|
104
|
+
let(:plain) { File.read(file) }
|
105
|
+
|
106
|
+
before do
|
107
|
+
Launchy.should_receive(:open)
|
108
|
+
|
109
|
+
Mail.deliver do
|
110
|
+
from 'Foo foo@example.com'
|
111
|
+
to 'bar@example.com'
|
112
|
+
subject 'Hello'
|
113
|
+
body 'World!'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'creates plain html document' do
|
118
|
+
File.exist?(file)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'saves From filed' do
|
122
|
+
plain.should include("Foo foo@example.com")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'using deliver! method' do
|
127
|
+
let(:plain_file) { Dir["#{location}/*/plain.html"].first }
|
128
|
+
let(:plain) { File.read(plain_file) }
|
129
|
+
|
130
|
+
before do
|
131
|
+
Launchy.should_receive(:open)
|
132
|
+
Mail.new do
|
133
|
+
from 'foo@example.com'
|
134
|
+
to 'bar@example.com'
|
135
|
+
subject 'Hello'
|
136
|
+
body 'World!'
|
137
|
+
end.deliver!
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'creates plain html document' do
|
141
|
+
File.exist?(plain_file).should be_true
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'saves From field' do
|
145
|
+
plain.should include("foo@example.com")
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'saves To field' do
|
149
|
+
plain.should include("bar@example.com")
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'saves Subject field' do
|
153
|
+
plain.should include("Hello")
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'saves Body field' do
|
157
|
+
plain.should include("World!")
|
158
|
+
end
|
48
159
|
end
|
49
160
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LetterOpener::Message do
|
4
|
+
let(:location) { File.expand_path('../../../tmp/letter_opener', __FILE__) }
|
5
|
+
|
6
|
+
describe '#reply_to' do
|
7
|
+
it 'handles one email as a string' do
|
8
|
+
message = described_class.new(location, mock(reply_to: 'test@example.com'))
|
9
|
+
message.reply_to.should eq('test@example.com')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'handles array of emails' do
|
13
|
+
message = described_class.new(location, mock(reply_to: ['test1@example.com', 'test2@example.com']))
|
14
|
+
message.reply_to.should eq('test1@example.com, test2@example.com')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#to' do
|
19
|
+
it 'handles one email as a string' do
|
20
|
+
message = described_class.new(location, mock(to: 'test@example.com'))
|
21
|
+
message.to.should eq('test@example.com')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'handles array of emails' do
|
25
|
+
message = described_class.new(location, mock(to: ['test1@example.com', 'test2@example.com']))
|
26
|
+
message.to.should eq('test1@example.com, test2@example.com')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,7 +3,9 @@ require 'bundler/setup'
|
|
3
3
|
Bundler.require(:default)
|
4
4
|
|
5
5
|
require "mail"
|
6
|
-
require "launchy"
|
7
6
|
|
8
7
|
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.filter_run :focus => true
|
10
|
+
config.run_all_when_everything_filtered = true
|
9
11
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: letter_opener
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,23 +9,27 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
default_executable:
|
12
|
+
date: 2012-10-01 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: launchy
|
17
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ! '>='
|
21
20
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
21
|
+
version: 2.0.4
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.0.4
|
26
30
|
- !ruby/object:Gem::Dependency
|
27
31
|
name: rspec
|
28
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
29
33
|
none: false
|
30
34
|
requirements:
|
31
35
|
- - ~>
|
@@ -33,10 +37,15 @@ dependencies:
|
|
33
37
|
version: 2.6.0
|
34
38
|
type: :development
|
35
39
|
prerelease: false
|
36
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.6.0
|
37
46
|
- !ruby/object:Gem::Dependency
|
38
47
|
name: mail
|
39
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
40
49
|
none: false
|
41
50
|
requirements:
|
42
51
|
- - ~>
|
@@ -44,7 +53,12 @@ dependencies:
|
|
44
53
|
version: 2.3.0
|
45
54
|
type: :development
|
46
55
|
prerelease: false
|
47
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.3.0
|
48
62
|
description: When mail is sent from your application, Letter Opener will open a preview
|
49
63
|
in the browser instead of sending.
|
50
64
|
email: ryan@railscasts.com
|
@@ -58,11 +72,13 @@ files:
|
|
58
72
|
- lib/letter_opener/railtie.rb
|
59
73
|
- lib/letter_opener.rb
|
60
74
|
- spec/letter_opener/delivery_method_spec.rb
|
75
|
+
- spec/letter_opener/message_spec.rb
|
61
76
|
- spec/spec_helper.rb
|
77
|
+
- CHANGELOG.md
|
62
78
|
- Gemfile
|
79
|
+
- LICENSE
|
63
80
|
- Rakefile
|
64
81
|
- README.rdoc
|
65
|
-
has_rdoc: true
|
66
82
|
homepage: http://github.com/ryanb/letter_opener
|
67
83
|
licenses: []
|
68
84
|
post_install_message:
|
@@ -83,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
99
|
version: 1.3.4
|
84
100
|
requirements: []
|
85
101
|
rubyforge_project: letter_opener
|
86
|
-
rubygems_version: 1.
|
102
|
+
rubygems_version: 1.8.23
|
87
103
|
signing_key:
|
88
104
|
specification_version: 3
|
89
105
|
summary: Preview mail in browser instead of sending.
|