mail_view 2.0.0 → 2.0.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.
- data/Gemfile.lock +1 -1
- data/lib/mail_view.rb +22 -12
- data/lib/mail_view/email.html.erb +31 -39
- data/mail_view.gemspec +1 -1
- data/test/test_mail_view.rb +47 -53
- metadata +1 -1
data/Gemfile.lock
CHANGED
data/lib/mail_view.rb
CHANGED
@@ -40,8 +40,8 @@ class MailView
|
|
40
40
|
mail = build_mail(name)
|
41
41
|
|
42
42
|
# Requested a specific bare MIME part. Render it verbatim.
|
43
|
-
if
|
44
|
-
if part = find_part(mail,
|
43
|
+
if part_type = request.params['part']
|
44
|
+
if part = find_part(mail, part_type)
|
45
45
|
body = part.body
|
46
46
|
body = body.decoded if body.respond_to?(:decoded)
|
47
47
|
ok body, part.content_type
|
@@ -51,10 +51,8 @@ class MailView
|
|
51
51
|
|
52
52
|
# Otherwise, show our message headers & frame the body.
|
53
53
|
else
|
54
|
-
part =
|
55
|
-
|
56
|
-
part_url = "#{request.path}?part=#{Rack::Utils.escape part_type}"
|
57
|
-
ok email_template.render(Object.new, :name => name, :mail => mail, :part => part, :part_url => part_url)
|
54
|
+
part = find_preferred_part(mail, [format, 'text/html', 'text/plain'])
|
55
|
+
ok email_template.render(Object.new, :name => name, :mail => mail, :part => part, :part_url => part_body_url(part))
|
58
56
|
end
|
59
57
|
else
|
60
58
|
not_found
|
@@ -105,15 +103,27 @@ class MailView
|
|
105
103
|
mail
|
106
104
|
end
|
107
105
|
|
106
|
+
def find_preferred_part(mail, formats)
|
107
|
+
found = nil
|
108
|
+
formats.find { |f| found = find_part(mail, f) }
|
109
|
+
found || mail
|
110
|
+
end
|
111
|
+
|
112
|
+
def part_body_url(part)
|
113
|
+
'?part=%s' % Rack::Utils.escape([part.main_type, part.sub_type].compact.join('/'))
|
114
|
+
end
|
115
|
+
|
108
116
|
def find_part(mail, matching_content_type)
|
109
117
|
if mail.multipart?
|
110
|
-
|
111
|
-
|
118
|
+
if matching_content_type.nil? && mail.sub_type == 'alternative'
|
119
|
+
mail.parts.last
|
120
|
+
else
|
121
|
+
found = nil
|
122
|
+
mail.parts.find { |part| found = find_part(part, matching_content_type) }
|
123
|
+
found
|
124
|
+
end
|
125
|
+
elsif matching_content_type && mail.content_type.to_s.match(matching_content_type)
|
112
126
|
mail
|
113
127
|
end
|
114
128
|
end
|
115
|
-
|
116
|
-
def all_parts(mail)
|
117
|
-
mail.respond_to?(:all_parts) ? mail.all_parts : mail.parts
|
118
|
-
end
|
119
129
|
end
|
@@ -7,13 +7,12 @@
|
|
7
7
|
padding: 10px 0 0 0;
|
8
8
|
margin: 0;
|
9
9
|
background: white;
|
10
|
-
font: 12px
|
10
|
+
font: 12px "Lucida Grande", sans-serif;
|
11
11
|
border-bottom: 1px solid #dedede;
|
12
12
|
overflow: hidden;
|
13
13
|
}
|
14
14
|
|
15
15
|
dl {
|
16
|
-
float: left;
|
17
16
|
margin: 0 0 10px 0;
|
18
17
|
padding: 0;
|
19
18
|
}
|
@@ -24,7 +23,6 @@
|
|
24
23
|
float: left;
|
25
24
|
clear: left;
|
26
25
|
text-align: right;
|
27
|
-
font-weight: bold;
|
28
26
|
color: #7f7f7f;
|
29
27
|
}
|
30
28
|
|
@@ -33,15 +31,6 @@
|
|
33
31
|
padding: 1px;
|
34
32
|
}
|
35
33
|
|
36
|
-
nav {
|
37
|
-
float: right;
|
38
|
-
margin: 0;
|
39
|
-
}
|
40
|
-
|
41
|
-
nav a {
|
42
|
-
color: #09c;
|
43
|
-
}
|
44
|
-
|
45
34
|
iframe {
|
46
35
|
border: 0;
|
47
36
|
width: 100%;
|
@@ -53,11 +42,16 @@
|
|
53
42
|
<body>
|
54
43
|
<header>
|
55
44
|
<dl>
|
56
|
-
<% if mail.respond_to?(:smtp_envelope_from) && mail.from != mail.smtp_envelope_from %>
|
45
|
+
<% if mail.respond_to?(:smtp_envelope_from) && Array(mail.from) != Array(mail.smtp_envelope_from) %>
|
57
46
|
<dt>SMTP-From:</dt>
|
58
47
|
<dd><%= mail.smtp_envelope_from %></dd>
|
59
48
|
<% end %>
|
60
49
|
|
50
|
+
<% if mail.respond_to?(:smtp_envelope_to) && mail.to != mail.smtp_envelope_to %>
|
51
|
+
<dt>SMTP-To:</dt>
|
52
|
+
<dd><%= mail.smtp_envelope_to %></dd>
|
53
|
+
<% end %>
|
54
|
+
|
61
55
|
<dt>From:</dt>
|
62
56
|
<dd><%= Rack::Utils.escape_html(mail.header['from'].to_s) %></dd>
|
63
57
|
|
@@ -66,41 +60,39 @@
|
|
66
60
|
<dd><%= Rack::Utils.escape_html(mail.header['reply-to'].to_s) %></dd>
|
67
61
|
<% end %>
|
68
62
|
|
69
|
-
<dt>
|
70
|
-
<dd
|
63
|
+
<dt>To:</dt>
|
64
|
+
<dd><%= Rack::Utils.escape_html(mail.header['to'].to_s) %></dd>
|
65
|
+
|
66
|
+
<% if mail.cc %>
|
67
|
+
<dt>CC:</dt>
|
68
|
+
<dd><%= Rack::Utils.escape_html(mail.header['cc'].to_s) %></dd>
|
69
|
+
<% end %>
|
71
70
|
|
72
71
|
<dt>Date:</dt>
|
73
72
|
<dd><%= Time.now.strftime("%b %e, %Y %I:%M:%S %p %Z") %></dd>
|
74
73
|
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
<dt>Subject:</dt>
|
75
|
+
<dd><strong><%= mail.subject %></strong></dd>
|
76
|
+
|
77
|
+
<% unless mail.attachments.nil? || mail.attachments.empty? %>
|
78
|
+
<dt>Attachments:</dt>
|
79
|
+
<dd>
|
80
|
+
<%= Rack::Utils.escape_html mail.attachments.map { |a| a.respond_to?(:original_filename) ? a.original_filename : a.filename }.inspect %>
|
81
|
+
</dd>
|
78
82
|
<% end %>
|
79
83
|
|
80
|
-
|
81
|
-
|
84
|
+
<% if mail.multipart? %>
|
85
|
+
<dd>
|
86
|
+
<select onchange="top.messageBody.location=this.options[this.selectedIndex].value;">
|
87
|
+
<option value="?part=text%2Fhtml">View as HTML email</option>
|
88
|
+
<option value="?part=text%2Fplain">View as plain-text email</option>
|
89
|
+
</select>
|
90
|
+
</dd>
|
91
|
+
<% end %>
|
82
92
|
</dl>
|
83
|
-
|
84
|
-
<% if mail.multipart? %>
|
85
|
-
<nav>
|
86
|
-
<% if part.content_type && part.content_type.match(/text\/html/) %>
|
87
|
-
<a href="<%= name %>.txt">View plain text version</a>
|
88
|
-
<% else %>
|
89
|
-
<a href="<%= name %>.html">View HTML version</a>
|
90
|
-
<% end %>
|
91
|
-
</nav>
|
92
|
-
<% end %>
|
93
|
-
|
94
|
-
<% unless mail.attachments.nil? || mail.attachments.empty? %>
|
95
|
-
<ul>
|
96
|
-
<% mail.attachments.each do |attachment| %>
|
97
|
-
<%= Rack::Utils.escape_html(attachment.respond_to?(:original_filename) ? attachment.original_filename : attachment.filename) %>
|
98
|
-
<% end %>
|
99
|
-
</ul>
|
100
|
-
<% end %>
|
101
93
|
</header>
|
102
94
|
|
103
|
-
<iframe seamless src="<%= part_url %>"></iframe>
|
95
|
+
<iframe seamless name="messageBody" src="<%= part_url %>"></iframe>
|
104
96
|
|
105
97
|
</body>
|
106
98
|
</html>
|
data/mail_view.gemspec
CHANGED
data/test/test_mail_view.rb
CHANGED
@@ -14,6 +14,7 @@ class TestMailView < Test::Unit::TestCase
|
|
14
14
|
Mail.new do
|
15
15
|
to 'josh@37signals.com'
|
16
16
|
body 'Hello'
|
17
|
+
yield self if block_given?
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
@@ -47,6 +48,8 @@ class TestMailView < Test::Unit::TestCase
|
|
47
48
|
Mail.new do
|
48
49
|
to 'josh@37signals.com'
|
49
50
|
|
51
|
+
yield self if block_given?
|
52
|
+
|
50
53
|
text_part do
|
51
54
|
body 'This is plain text'
|
52
55
|
end
|
@@ -70,20 +73,20 @@ class TestMailView < Test::Unit::TestCase
|
|
70
73
|
text_part do
|
71
74
|
body 'This is plain text'
|
72
75
|
end
|
73
|
-
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
77
79
|
def multipart_mixed_with_text_and_attachment
|
78
|
-
|
80
|
+
plain_text_message { |mail| add_attachments_to mail }
|
79
81
|
end
|
80
82
|
|
81
83
|
def multipart_mixed_with_multipart_alternative_and_attachment
|
82
|
-
|
84
|
+
multipart_alternative { |mail| add_attachments_to mail }
|
83
85
|
end
|
84
86
|
|
85
|
-
def
|
86
|
-
mail.
|
87
|
+
def add_attachments_to(mail)
|
88
|
+
mail.add_file :filename => 'checkbox.png', :content => 'stub'
|
89
|
+
mail.add_file :filename => 'foo.vcf', :content => 'stub'
|
87
90
|
mail
|
88
91
|
end
|
89
92
|
|
@@ -128,8 +131,8 @@ class TestMailView < Test::Unit::TestCase
|
|
128
131
|
Preview
|
129
132
|
end
|
130
133
|
|
131
|
-
def iframe_src_match(
|
132
|
-
/<iframe[^>]* src="
|
134
|
+
def iframe_src_match(content_type)
|
135
|
+
/<iframe[^>]* src="\?part=#{Regexp.escape(Rack::Utils.escape(content_type))}"[^>]*><\/iframe>/
|
133
136
|
end
|
134
137
|
|
135
138
|
def unescaped_body
|
@@ -168,10 +171,10 @@ class TestMailView < Test::Unit::TestCase
|
|
168
171
|
def test_plain_text_message
|
169
172
|
get '/plain_text_message'
|
170
173
|
assert last_response.ok?
|
171
|
-
|
172
|
-
|
174
|
+
assert_match iframe_src_match(''), last_response.body
|
175
|
+
assert_no_match %r(View as), last_response.body
|
173
176
|
|
174
|
-
get
|
177
|
+
get '/plain_text_message?part='
|
175
178
|
assert last_response.ok?
|
176
179
|
assert_match 'Hello', last_response.body
|
177
180
|
end
|
@@ -179,10 +182,10 @@ class TestMailView < Test::Unit::TestCase
|
|
179
182
|
def test_mounted_plain_text_message
|
180
183
|
get '/plain_text_message', {}, 'SCRIPT_NAME' => '/boom'
|
181
184
|
assert last_response.ok?
|
182
|
-
|
183
|
-
|
185
|
+
assert_match iframe_src_match(''), last_response.body
|
186
|
+
assert_no_match %r(View as), last_response.body
|
184
187
|
|
185
|
-
get
|
188
|
+
get '/boom/plain_text_message?part='
|
186
189
|
assert last_response.ok?
|
187
190
|
assert_equal 'Hello', last_response.body
|
188
191
|
end
|
@@ -197,10 +200,10 @@ class TestMailView < Test::Unit::TestCase
|
|
197
200
|
def test_html_message
|
198
201
|
get '/html_message'
|
199
202
|
assert last_response.ok?
|
200
|
-
|
201
|
-
|
203
|
+
assert_match iframe_src_match('text/html'), last_response.body
|
204
|
+
assert_no_match %r(View as), last_response.body
|
202
205
|
|
203
|
-
get
|
206
|
+
get '/html_message?part=text%2Fhtml'
|
204
207
|
assert last_response.ok?
|
205
208
|
assert_equal '<h1>Hello</h1>', last_response.body
|
206
209
|
end
|
@@ -208,10 +211,10 @@ class TestMailView < Test::Unit::TestCase
|
|
208
211
|
def test_nested_multipart_message
|
209
212
|
get '/nested_multipart_message'
|
210
213
|
assert last_response.ok?
|
211
|
-
|
212
|
-
assert_match
|
214
|
+
assert_match iframe_src_match('text/html'), last_response.body
|
215
|
+
assert_match %r(View as), last_response.body
|
213
216
|
|
214
|
-
get
|
217
|
+
get '/nested_multipart_message?part=text%2Fhtml'
|
215
218
|
assert last_response.ok?
|
216
219
|
assert_equal '<h1>Hello</h1>', last_response.body
|
217
220
|
end
|
@@ -219,11 +222,10 @@ class TestMailView < Test::Unit::TestCase
|
|
219
222
|
def test_multipart_alternative
|
220
223
|
get '/multipart_alternative'
|
221
224
|
assert last_response.ok?
|
222
|
-
|
223
|
-
assert_match
|
224
|
-
assert_match 'View plain text version', last_response.body
|
225
|
+
assert_match iframe_src_match('text/html'), last_response.body
|
226
|
+
assert_match 'View as', last_response.body
|
225
227
|
|
226
|
-
get
|
228
|
+
get '/multipart_alternative?part=text%2Fhtml'
|
227
229
|
assert last_response.ok?
|
228
230
|
assert_equal '<h1>This is HTML</h1>', last_response.body
|
229
231
|
end
|
@@ -231,11 +233,10 @@ class TestMailView < Test::Unit::TestCase
|
|
231
233
|
def test_multipart_alternative_as_html
|
232
234
|
get '/multipart_alternative.html'
|
233
235
|
assert last_response.ok?
|
234
|
-
|
235
|
-
assert_match
|
236
|
-
assert_match 'View plain text version', last_response.body
|
236
|
+
assert_match iframe_src_match('text/html'), last_response.body
|
237
|
+
assert_match 'View as', last_response.body
|
237
238
|
|
238
|
-
get
|
239
|
+
get '/multipart_alternative.html?part=text%2Fhtml'
|
239
240
|
assert last_response.ok?
|
240
241
|
assert_equal '<h1>This is HTML</h1>', last_response.body
|
241
242
|
end
|
@@ -243,11 +244,10 @@ class TestMailView < Test::Unit::TestCase
|
|
243
244
|
def test_multipart_alternative_as_text
|
244
245
|
get '/multipart_alternative.txt'
|
245
246
|
assert last_response.ok?
|
246
|
-
|
247
|
-
assert_match
|
248
|
-
assert_match 'View HTML version', last_response.body
|
247
|
+
assert_match iframe_src_match('text/plain'), last_response.body
|
248
|
+
assert_match 'View as', last_response.body
|
249
249
|
|
250
|
-
get
|
250
|
+
get '/multipart_alternative.txt?part=text%2Fplain'
|
251
251
|
assert last_response.ok?
|
252
252
|
assert_equal 'This is plain text', last_response.body
|
253
253
|
end
|
@@ -255,11 +255,10 @@ class TestMailView < Test::Unit::TestCase
|
|
255
255
|
def test_multipart_alternative_text_as_default
|
256
256
|
get '/multipart_alternative_text_default'
|
257
257
|
assert last_response.ok?
|
258
|
-
|
259
|
-
assert_match
|
260
|
-
assert_match 'View HTML version', last_response.body
|
258
|
+
assert_match iframe_src_match('text/plain'), last_response.body
|
259
|
+
assert_match 'View as', last_response.body
|
261
260
|
|
262
|
-
get
|
261
|
+
get '/multipart_alternative_text_default?part=text%2Fplain'
|
263
262
|
assert last_response.ok?
|
264
263
|
assert_equal 'This is plain text', last_response.body
|
265
264
|
end
|
@@ -267,13 +266,11 @@ class TestMailView < Test::Unit::TestCase
|
|
267
266
|
def test_multipart_mixed_with_text_and_attachment
|
268
267
|
get '/multipart_mixed_with_text_and_attachment'
|
269
268
|
assert last_response.ok?
|
270
|
-
|
271
|
-
|
272
|
-
assert_no_match %r(View HTML version), last_response.body
|
273
|
-
assert_no_match %r(View plain text version), last_response.body
|
269
|
+
assert_match iframe_src_match('text/plain'), last_response.body
|
270
|
+
#assert_no_match %r(View as), last_response.body
|
274
271
|
assert_match 'checkbox.png', last_response.body
|
275
272
|
|
276
|
-
get
|
273
|
+
get '/multipart_mixed_with_text_and_attachment?part=text%2Fplain'
|
277
274
|
assert last_response.ok?
|
278
275
|
assert_equal 'Hello', last_response.body
|
279
276
|
end
|
@@ -281,12 +278,11 @@ class TestMailView < Test::Unit::TestCase
|
|
281
278
|
def test_multipart_mixed_with_multipart_alternative_and_attachment
|
282
279
|
get '/multipart_mixed_with_multipart_alternative_and_attachment'
|
283
280
|
assert last_response.ok?
|
284
|
-
|
285
|
-
assert_match
|
286
|
-
assert_match 'View plain text version', last_response.body
|
281
|
+
assert_match iframe_src_match('text/html'), last_response.body
|
282
|
+
assert_match 'View as', last_response.body
|
287
283
|
assert_match 'checkbox.png', last_response.body
|
288
284
|
|
289
|
-
get
|
285
|
+
get '/multipart_mixed_with_multipart_alternative_and_attachment?part=text%2Fhtml'
|
290
286
|
assert last_response.ok?
|
291
287
|
assert_equal '<h1>This is HTML</h1>', last_response.body
|
292
288
|
end
|
@@ -294,12 +290,11 @@ class TestMailView < Test::Unit::TestCase
|
|
294
290
|
def test_multipart_mixed_with_multipart_alternative_and_attachment_preferring_plain_text
|
295
291
|
get '/multipart_mixed_with_multipart_alternative_and_attachment.txt'
|
296
292
|
assert last_response.ok?
|
297
|
-
|
298
|
-
assert_match
|
299
|
-
assert_match 'View HTML version', last_response.body
|
293
|
+
assert_match iframe_src_match('text/plain'), last_response.body
|
294
|
+
assert_match 'View as', last_response.body
|
300
295
|
assert_match 'checkbox.png', last_response.body
|
301
296
|
|
302
|
-
get
|
297
|
+
get '/multipart_mixed_with_multipart_alternative_and_attachment.txt?part=text%2Fplain'
|
303
298
|
assert last_response.ok?
|
304
299
|
assert_equal 'This is plain text', last_response.body
|
305
300
|
end
|
@@ -315,10 +310,9 @@ class TestMailView < Test::Unit::TestCase
|
|
315
310
|
def test_tmail_html_message
|
316
311
|
get '/tmail_html_message'
|
317
312
|
assert last_response.ok?
|
318
|
-
|
319
|
-
assert_match iframe_src_match(body_path), last_response.body
|
313
|
+
assert_match iframe_src_match('text/html'), last_response.body
|
320
314
|
|
321
|
-
get
|
315
|
+
get '/tmail_html_message?part=text%2Fhtml'
|
322
316
|
assert last_response.ok?
|
323
317
|
assert_equal '<h1>Hello</h1>', last_response.body
|
324
318
|
end
|
@@ -327,8 +321,8 @@ class TestMailView < Test::Unit::TestCase
|
|
327
321
|
get '/tmail_multipart_alternative'
|
328
322
|
assert last_response.ok?
|
329
323
|
body_path = '/tmail_multipart_alternative?part=text%2Fhtml'
|
330
|
-
assert_match iframe_src_match(
|
331
|
-
assert_match 'View
|
324
|
+
assert_match iframe_src_match('text/html'), last_response.body
|
325
|
+
assert_match 'View as', last_response.body
|
332
326
|
|
333
327
|
get body_path
|
334
328
|
assert last_response.ok?
|