mailcatcher 0.5.8 → 0.5.9
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/lib/mail_catcher.rb +16 -20
- data/lib/mail_catcher/events.rb +1 -1
- data/lib/mail_catcher/growl.rb +1 -2
- data/lib/mail_catcher/mail.rb +32 -33
- data/lib/mail_catcher/smtp.rb +4 -1
- data/lib/mail_catcher/version.rb +3 -0
- data/public/favicon.ico +0 -0
- data/public/stylesheets/application.css +355 -279
- metadata +32 -36
- data/VERSION +0 -1
data/lib/mail_catcher.rb
CHANGED
@@ -1,22 +1,13 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
require 'active_support/all'
|
1
|
+
require 'active_support/core_ext'
|
4
2
|
require 'eventmachine'
|
3
|
+
require 'open3'
|
5
4
|
require 'optparse'
|
6
5
|
require 'rbconfig'
|
7
6
|
require 'thin'
|
8
7
|
|
9
|
-
|
10
|
-
extend ActiveSupport::Autoload
|
11
|
-
|
12
|
-
autoload :Events
|
13
|
-
autoload :Growl
|
14
|
-
autoload :Mail
|
15
|
-
autoload :Smtp
|
16
|
-
autoload :Web
|
17
|
-
|
18
|
-
module_function
|
8
|
+
require 'mail_catcher/version'
|
19
9
|
|
10
|
+
module MailCatcher extend self
|
20
11
|
def which command
|
21
12
|
Open3.popen3 'which', 'command' do |stdin, stdout, stderr|
|
22
13
|
return stdout.read.chomp.presence
|
@@ -55,7 +46,7 @@ module_function
|
|
55
46
|
end
|
56
47
|
end
|
57
48
|
|
58
|
-
|
49
|
+
@defaults = {
|
59
50
|
:smtp_ip => '127.0.0.1',
|
60
51
|
:smtp_port => '1025',
|
61
52
|
:http_ip => '127.0.0.1',
|
@@ -66,11 +57,11 @@ module_function
|
|
66
57
|
:browse => false,
|
67
58
|
}
|
68
59
|
|
69
|
-
def parse! arguments=ARGV, defaults
|
70
|
-
|
60
|
+
def parse! arguments=ARGV, defaults=@defaults
|
61
|
+
@defaults.dup.tap do |options|
|
71
62
|
OptionParser.new do |parser|
|
72
63
|
parser.banner = "Usage: mailcatcher [options]"
|
73
|
-
parser.version =
|
64
|
+
parser.version = VERSION
|
74
65
|
|
75
66
|
parser.on("--ip IP", "Set the ip address of both servers") do |ip|
|
76
67
|
options[:smtp_ip] = options[:http_ip] = ip
|
@@ -131,7 +122,7 @@ module_function
|
|
131
122
|
|
132
123
|
def run! options=nil
|
133
124
|
# If we are passed options, fill in the blanks
|
134
|
-
options &&=
|
125
|
+
options &&= @defaults.merge options
|
135
126
|
# Otherwise, parse them from ARGV
|
136
127
|
options ||= parse!
|
137
128
|
|
@@ -182,7 +173,6 @@ module_function
|
|
182
173
|
end
|
183
174
|
|
184
175
|
protected
|
185
|
-
module_function
|
186
176
|
|
187
177
|
def rescue_port port
|
188
178
|
begin
|
@@ -192,10 +182,16 @@ module_function
|
|
192
182
|
rescue RuntimeError
|
193
183
|
if $!.to_s =~ /\bno acceptor\b/
|
194
184
|
puts "~~> ERROR: Something's using port #{port}. Are you already running MailCatcher?"
|
195
|
-
exit
|
185
|
+
exit(-1)
|
196
186
|
else
|
197
187
|
raise
|
198
188
|
end
|
199
189
|
end
|
200
190
|
end
|
201
191
|
end
|
192
|
+
|
193
|
+
require 'mail_catcher/events'
|
194
|
+
require 'mail_catcher/growl'
|
195
|
+
require 'mail_catcher/mail'
|
196
|
+
require 'mail_catcher/smtp'
|
197
|
+
require 'mail_catcher/web'
|
data/lib/mail_catcher/events.rb
CHANGED
data/lib/mail_catcher/growl.rb
CHANGED
data/lib/mail_catcher/mail.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
+
require 'active_support/json'
|
1
2
|
require 'mail'
|
2
3
|
require 'sqlite3'
|
3
4
|
require 'eventmachine'
|
4
5
|
|
5
|
-
module MailCatcher::Mail
|
6
|
-
module_function
|
7
|
-
|
6
|
+
module MailCatcher::Mail extend self
|
8
7
|
def db
|
9
|
-
|
8
|
+
@__db ||= begin
|
10
9
|
SQLite3::Database.new(':memory:', :type_translation => true).tap do |db|
|
11
10
|
db.execute(<<-SQL)
|
12
11
|
CREATE TABLE message (
|
@@ -39,10 +38,10 @@ module_function
|
|
39
38
|
end
|
40
39
|
|
41
40
|
def add_message(message)
|
42
|
-
|
41
|
+
@add_message_query ||= db.prepare("INSERT INTO message (sender, recipients, subject, source, type, size, created_at) VALUES (?, ?, ?, ?, ?, ?, datetime('now'))")
|
43
42
|
|
44
43
|
mail = Mail.new(message[:source])
|
45
|
-
|
44
|
+
@add_message_query.execute(message[:sender], message[:recipients].to_json, mail.subject, message[:source], mail.mime_type || 'text/plain', message[:source].length)
|
46
45
|
message_id = db.last_insert_row_id
|
47
46
|
parts = mail.all_parts
|
48
47
|
parts = [mail] if parts.empty?
|
@@ -60,18 +59,18 @@ module_function
|
|
60
59
|
end
|
61
60
|
|
62
61
|
def add_message_part(*args)
|
63
|
-
|
64
|
-
|
62
|
+
@add_message_part_query ||= db.prepare "INSERT INTO message_part (message_id, cid, type, is_attachment, filename, charset, body, size, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))"
|
63
|
+
@add_message_part_query.execute(*args)
|
65
64
|
end
|
66
65
|
|
67
66
|
def latest_created_at
|
68
|
-
|
69
|
-
|
67
|
+
@latest_created_at_query ||= db.prepare "SELECT created_at FROM message ORDER BY created_at DESC LIMIT 1"
|
68
|
+
@latest_created_at_query.execute.next
|
70
69
|
end
|
71
70
|
|
72
71
|
def messages
|
73
|
-
|
74
|
-
|
72
|
+
@messages_query ||= db.prepare "SELECT id, sender, recipients, subject, size, created_at FROM message ORDER BY created_at ASC"
|
73
|
+
@messages_query.execute.map do |row|
|
75
74
|
Hash[row.fields.zip(row)].tap do |message|
|
76
75
|
message["recipients"] &&= ActiveSupport::JSON.decode message["recipients"]
|
77
76
|
end
|
@@ -79,46 +78,46 @@ module_function
|
|
79
78
|
end
|
80
79
|
|
81
80
|
def message(id)
|
82
|
-
|
83
|
-
row =
|
81
|
+
@message_query ||= db.prepare "SELECT * FROM message WHERE id = ? LIMIT 1"
|
82
|
+
row = @message_query.execute(id).next
|
84
83
|
row && Hash[row.fields.zip(row)].tap do |message|
|
85
84
|
message["recipients"] &&= ActiveSupport::JSON.decode message["recipients"]
|
86
85
|
end
|
87
86
|
end
|
88
87
|
|
89
88
|
def message_has_html?(id)
|
90
|
-
|
91
|
-
(
|
89
|
+
@message_has_html_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type IN ('application/xhtml+xml', 'text/html') LIMIT 1"
|
90
|
+
(!!@message_has_html_query.execute(id).next) || ['text/html', 'application/xhtml+xml'].include?(message(id)["type"])
|
92
91
|
end
|
93
92
|
|
94
93
|
def message_has_plain?(id)
|
95
|
-
|
96
|
-
(
|
94
|
+
@message_has_plain_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type = 'text/plain' LIMIT 1"
|
95
|
+
(!!@message_has_plain_query.execute(id).next) || message(id)["type"] == "text/plain"
|
97
96
|
end
|
98
97
|
|
99
98
|
def message_parts(id)
|
100
|
-
|
101
|
-
|
99
|
+
@message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? ORDER BY filename ASC"
|
100
|
+
@message_parts_query.execute(id).map do |row|
|
102
101
|
Hash[row.fields.zip(row)]
|
103
102
|
end
|
104
103
|
end
|
105
104
|
|
106
105
|
def message_attachments(id)
|
107
|
-
|
108
|
-
|
106
|
+
@message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? AND is_attachment = 1 ORDER BY filename ASC"
|
107
|
+
@message_parts_query.execute(id).map do |row|
|
109
108
|
Hash[row.fields.zip(row)]
|
110
109
|
end
|
111
110
|
end
|
112
111
|
|
113
112
|
def message_part(message_id, part_id)
|
114
|
-
|
115
|
-
row =
|
113
|
+
@message_part_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND id = ? LIMIT 1"
|
114
|
+
row = @message_part_query.execute(message_id, part_id).next
|
116
115
|
row && Hash[row.fields.zip(row)]
|
117
116
|
end
|
118
117
|
|
119
118
|
def message_part_type(message_id, part_type)
|
120
|
-
|
121
|
-
row =
|
119
|
+
@message_part_type_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND type = ? AND is_attachment = 0 LIMIT 1"
|
120
|
+
row = @message_part_type_query.execute(message_id, part_type).next
|
122
121
|
row && Hash[row.fields.zip(row)]
|
123
122
|
end
|
124
123
|
|
@@ -136,19 +135,19 @@ module_function
|
|
136
135
|
end
|
137
136
|
|
138
137
|
def message_part_cid(message_id, cid)
|
139
|
-
|
140
|
-
|
141
|
-
|
138
|
+
@message_part_cid_query ||= db.prepare 'SELECT * FROM message_part WHERE message_id = ?'
|
139
|
+
@message_part_cid_query.execute(message_id).map do |row|
|
140
|
+
Hash[row.fields.zip(row)]
|
142
141
|
end.find do |part|
|
143
142
|
part["cid"] == cid
|
144
143
|
end
|
145
144
|
end
|
146
145
|
|
147
146
|
def delete!
|
148
|
-
|
149
|
-
|
147
|
+
@delete_messages_query ||= db.prepare 'DELETE FROM message'
|
148
|
+
@delete_message_parts_query ||= db.prepare 'DELETE FROM message_part'
|
150
149
|
|
151
|
-
|
152
|
-
|
150
|
+
@delete_messages_query.execute and
|
151
|
+
@delete_message_parts_query.execute
|
153
152
|
end
|
154
153
|
end
|
data/lib/mail_catcher/smtp.rb
CHANGED
@@ -34,7 +34,10 @@ class MailCatcher::Smtp < EventMachine::Protocols::SmtpServer
|
|
34
34
|
|
35
35
|
def receive_data_chunk(lines)
|
36
36
|
current_message[:source] ||= ""
|
37
|
-
|
37
|
+
lines.each do |line|
|
38
|
+
# RFC821 4.5.2 says leading periods should be stripped from the body data.
|
39
|
+
current_message[:source] << line.sub(/\A\./, "") << "\n"
|
40
|
+
end
|
38
41
|
true
|
39
42
|
end
|
40
43
|
|
data/public/favicon.ico
ADDED
Binary file
|
@@ -16,77 +16,93 @@ time, mark, audio, video {
|
|
16
16
|
border: 0;
|
17
17
|
font-size: 100%;
|
18
18
|
font: inherit;
|
19
|
-
vertical-align: baseline;
|
19
|
+
vertical-align: baseline;
|
20
|
+
}
|
20
21
|
|
21
22
|
body {
|
22
|
-
line-height: 1;
|
23
|
+
line-height: 1;
|
24
|
+
}
|
23
25
|
|
24
26
|
ol, ul {
|
25
|
-
list-style: none;
|
27
|
+
list-style: none;
|
28
|
+
}
|
26
29
|
|
27
30
|
table {
|
28
31
|
border-collapse: collapse;
|
29
|
-
border-spacing: 0;
|
32
|
+
border-spacing: 0;
|
33
|
+
}
|
30
34
|
|
31
35
|
caption, th, td {
|
32
36
|
text-align: left;
|
33
37
|
font-weight: normal;
|
34
|
-
vertical-align: middle;
|
38
|
+
vertical-align: middle;
|
39
|
+
}
|
35
40
|
|
36
41
|
q, blockquote {
|
37
|
-
quotes: none;
|
38
|
-
|
39
|
-
|
40
|
-
|
42
|
+
quotes: none;
|
43
|
+
}
|
44
|
+
q:before, q:after, blockquote:before, blockquote:after {
|
45
|
+
content: "";
|
46
|
+
content: none;
|
47
|
+
}
|
41
48
|
|
42
49
|
a img {
|
43
|
-
border: none;
|
50
|
+
border: none;
|
51
|
+
}
|
44
52
|
|
45
53
|
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary {
|
46
|
-
display: block;
|
54
|
+
display: block;
|
55
|
+
}
|
47
56
|
|
48
57
|
html, body {
|
49
58
|
width: 100%;
|
50
|
-
height: 100%;
|
59
|
+
height: 100%;
|
60
|
+
}
|
51
61
|
|
52
62
|
body {
|
53
|
-
display: -moz-box;
|
54
63
|
display: -webkit-box;
|
64
|
+
display: -moz-box;
|
55
65
|
display: -ms-box;
|
56
66
|
display: box;
|
57
|
-
-moz-box-orient: vertical;
|
58
67
|
-webkit-box-orient: vertical;
|
68
|
+
-moz-box-orient: vertical;
|
59
69
|
-ms-box-orient: vertical;
|
60
70
|
box-orient: vertical;
|
61
71
|
background: #eeeeee;
|
62
72
|
color: black;
|
63
73
|
font-size: 12px;
|
64
|
-
font-family: Helvetica, sans-serif;
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
74
|
+
font-family: Helvetica, sans-serif;
|
75
|
+
}
|
76
|
+
body body {
|
77
|
+
font-size: 75%;
|
78
|
+
line-height: 2em;
|
79
|
+
}
|
80
|
+
body html > body {
|
81
|
+
font-size: 12px;
|
82
|
+
}
|
83
|
+
body.iframe {
|
84
|
+
background: white;
|
85
|
+
}
|
86
|
+
body.iframe h1 {
|
87
|
+
font-size: 1.3em;
|
88
|
+
margin: 12px;
|
89
|
+
}
|
90
|
+
body.iframe p, body.iframe form {
|
91
|
+
margin: 0 12px 12px 12px;
|
92
|
+
line-height: 1.25;
|
93
|
+
}
|
94
|
+
body.iframe .loading {
|
95
|
+
color: #666666;
|
96
|
+
margin-left: 0.5em;
|
97
|
+
}
|
81
98
|
|
82
99
|
.button {
|
83
100
|
padding: 0.5em 1em;
|
84
101
|
border: 1px solid #cccccc;
|
85
|
-
-moz-border-radius: 2px;
|
86
102
|
-webkit-border-radius: 2px;
|
87
|
-
-
|
103
|
+
-moz-border-radius: 2px;
|
88
104
|
-ms-border-radius: 2px;
|
89
|
-
-
|
105
|
+
-o-border-radius: 2px;
|
90
106
|
border-radius: 2px;
|
91
107
|
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f4f4), color-stop(100%, #ececec)), #ececec;
|
92
108
|
background: -webkit-linear-gradient(#f4f4f4, #ececec), #ececec;
|
@@ -96,99 +112,115 @@ body {
|
|
96
112
|
background: linear-gradient(#f4f4f4, #ececec), #ececec;
|
97
113
|
color: #666666;
|
98
114
|
text-shadow: 1px 1px 0 white;
|
99
|
-
text-decoration: none;
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
115
|
+
text-decoration: none;
|
116
|
+
}
|
117
|
+
.button:hover, .button:focus {
|
118
|
+
border-color: #999999;
|
119
|
+
border-bottom-color: #666666;
|
120
|
+
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eeeeee), color-stop(100%, #dddddd)), #dddddd;
|
121
|
+
background: -webkit-linear-gradient(#eeeeee, #dddddd), #dddddd;
|
122
|
+
background: -moz-linear-gradient(#eeeeee, #dddddd), #dddddd;
|
123
|
+
background: -o-linear-gradient(#eeeeee, #dddddd), #dddddd;
|
124
|
+
background: -ms-linear-gradient(#eeeeee, #dddddd), #dddddd;
|
125
|
+
background: linear-gradient(#eeeeee, #dddddd), #dddddd;
|
126
|
+
color: #333333;
|
127
|
+
text-decoration: none;
|
128
|
+
}
|
129
|
+
.button:active, .button.active {
|
130
|
+
border-color: #666666;
|
131
|
+
border-bottom-color: #999999;
|
132
|
+
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dddddd), color-stop(100%, #eeeeee)), #eeeeee;
|
133
|
+
background: -webkit-linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
134
|
+
background: -moz-linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
135
|
+
background: -o-linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
136
|
+
background: -ms-linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
137
|
+
background: linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
138
|
+
color: #333333;
|
139
|
+
text-decoration: none;
|
140
|
+
text-shadow: -1px -1px 0 #eeeeee;
|
141
|
+
}
|
123
142
|
|
124
143
|
body > header {
|
125
144
|
overflow: hidden;
|
126
145
|
*zoom: 1;
|
127
|
-
border-bottom: 1px solid #cccccc;
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
146
|
+
border-bottom: 1px solid #cccccc;
|
147
|
+
}
|
148
|
+
body > header h1 {
|
149
|
+
float: left;
|
150
|
+
margin-left: 6px;
|
151
|
+
padding: 6px;
|
152
|
+
padding-left: 30px;
|
153
|
+
background: url(/images/logo.png) left no-repeat;
|
154
|
+
font-size: 18px;
|
155
|
+
font-weight: bold;
|
156
|
+
}
|
157
|
+
body > header h1 a {
|
158
|
+
color: black;
|
159
|
+
text-decoration: none;
|
160
|
+
text-shadow: 0 1px 0 white;
|
161
|
+
-webkit-transition: 0.1s ease;
|
162
|
+
-moz-transition: 0.1s ease;
|
163
|
+
-ms-transition: 0.1s ease;
|
164
|
+
-o-transition: 0.1s ease;
|
165
|
+
transition: 0.1s ease;
|
166
|
+
}
|
167
|
+
body > header h1 a:hover {
|
168
|
+
color: #4183c4;
|
169
|
+
}
|
170
|
+
body > header nav {
|
171
|
+
border-left: 1px solid #cccccc;
|
172
|
+
}
|
173
|
+
body > header nav.project {
|
174
|
+
float: left;
|
175
|
+
}
|
176
|
+
body > header nav.app {
|
177
|
+
float: right;
|
178
|
+
}
|
179
|
+
body > header nav li {
|
180
|
+
display: block;
|
181
|
+
float: left;
|
182
|
+
border-left: 1px solid white;
|
183
|
+
border-right: 1px solid #cccccc;
|
184
|
+
}
|
185
|
+
body > header nav li input {
|
186
|
+
margin: 6px;
|
187
|
+
}
|
188
|
+
body > header nav li a {
|
189
|
+
display: block;
|
190
|
+
padding: 10px;
|
191
|
+
text-decoration: none;
|
192
|
+
text-shadow: 0 1px 0 white;
|
193
|
+
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f4f4), color-stop(100%, #ececec)), #ececec;
|
194
|
+
background: -webkit-linear-gradient(#f4f4f4, #ececec), #ececec;
|
195
|
+
background: -moz-linear-gradient(#f4f4f4, #ececec), #ececec;
|
196
|
+
background: -o-linear-gradient(#f4f4f4, #ececec), #ececec;
|
197
|
+
background: -ms-linear-gradient(#f4f4f4, #ececec), #ececec;
|
198
|
+
background: linear-gradient(#f4f4f4, #ececec), #ececec;
|
199
|
+
color: #666666;
|
200
|
+
text-shadow: 1px 1px 0 white;
|
201
|
+
text-decoration: none;
|
202
|
+
}
|
203
|
+
body > header nav li a:hover, body > header nav li a:focus {
|
204
|
+
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eeeeee), color-stop(100%, #dddddd)), #dddddd;
|
205
|
+
background: -webkit-linear-gradient(#eeeeee, #dddddd), #dddddd;
|
206
|
+
background: -moz-linear-gradient(#eeeeee, #dddddd), #dddddd;
|
207
|
+
background: -o-linear-gradient(#eeeeee, #dddddd), #dddddd;
|
208
|
+
background: -ms-linear-gradient(#eeeeee, #dddddd), #dddddd;
|
209
|
+
background: linear-gradient(#eeeeee, #dddddd), #dddddd;
|
210
|
+
color: #333333;
|
211
|
+
text-decoration: none;
|
212
|
+
}
|
213
|
+
body > header nav li a:active, body > header nav li a.active {
|
214
|
+
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dddddd), color-stop(100%, #eeeeee)), #eeeeee;
|
215
|
+
background: -webkit-linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
216
|
+
background: -moz-linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
217
|
+
background: -o-linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
218
|
+
background: -ms-linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
219
|
+
background: linear-gradient(#dddddd, #eeeeee), #eeeeee;
|
220
|
+
color: #333333;
|
221
|
+
text-decoration: none;
|
222
|
+
text-shadow: -1px -1px 0 #eeeeee;
|
223
|
+
}
|
192
224
|
|
193
225
|
#messages {
|
194
226
|
width: 100%;
|
@@ -196,182 +228,226 @@ body > header {
|
|
196
228
|
min-height: 3em;
|
197
229
|
overflow: auto;
|
198
230
|
background: white;
|
199
|
-
border-top: 1px solid white;
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
+
border-top: 1px solid white;
|
232
|
+
}
|
233
|
+
#messages table {
|
234
|
+
overflow: hidden;
|
235
|
+
*zoom: 1;
|
236
|
+
width: 100%;
|
237
|
+
}
|
238
|
+
#messages table thead tr {
|
239
|
+
background: #eeeeee;
|
240
|
+
color: #333333;
|
241
|
+
}
|
242
|
+
#messages table thead tr th {
|
243
|
+
padding: 0.25em;
|
244
|
+
font-weight: bold;
|
245
|
+
color: #666666;
|
246
|
+
text-shadow: 0 1px 0 white;
|
247
|
+
}
|
248
|
+
#messages table tbody tr {
|
249
|
+
cursor: pointer;
|
250
|
+
-webkit-transition: 0.1s ease;
|
251
|
+
-moz-transition: 0.1s ease;
|
252
|
+
-ms-transition: 0.1s ease;
|
253
|
+
-o-transition: 0.1s ease;
|
254
|
+
transition: 0.1s ease;
|
255
|
+
color: #333333;
|
256
|
+
}
|
257
|
+
#messages table tbody tr:hover {
|
258
|
+
color: black;
|
259
|
+
}
|
260
|
+
#messages table tbody tr:nth-child(even) {
|
261
|
+
background: #f0f0f0;
|
262
|
+
}
|
263
|
+
#messages table tbody tr.selected {
|
264
|
+
background: Highlight;
|
265
|
+
color: HighlightText;
|
266
|
+
}
|
267
|
+
#messages table tbody tr td {
|
268
|
+
padding: 0.25em;
|
269
|
+
}
|
270
|
+
#messages table tbody tr td.blank {
|
271
|
+
color: #666666;
|
272
|
+
font-style: italic;
|
273
|
+
}
|
231
274
|
|
232
275
|
#resizer {
|
233
276
|
padding-bottom: 5px;
|
234
|
-
cursor: ns-resize;
|
235
|
-
|
236
|
-
|
237
|
-
|
277
|
+
cursor: ns-resize;
|
278
|
+
}
|
279
|
+
#resizer .ruler {
|
280
|
+
border-top: 1px solid #cccccc;
|
281
|
+
border-bottom: 1px solid white;
|
282
|
+
}
|
238
283
|
|
239
284
|
#message {
|
240
|
-
display: -moz-box;
|
241
285
|
display: -webkit-box;
|
286
|
+
display: -moz-box;
|
242
287
|
display: -ms-box;
|
243
288
|
display: box;
|
244
|
-
-moz-box-orient: vertical;
|
245
289
|
-webkit-box-orient: vertical;
|
290
|
+
-moz-box-orient: vertical;
|
246
291
|
-ms-box-orient: vertical;
|
247
292
|
box-orient: vertical;
|
248
|
-
-moz-box-flex: 1;
|
249
293
|
-webkit-box-flex: 1;
|
294
|
+
-moz-box-flex: 1;
|
250
295
|
-ms-box-flex: 1;
|
251
|
-
box-flex: 1;
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
296
|
+
box-flex: 1;
|
297
|
+
}
|
298
|
+
#message > header {
|
299
|
+
overflow: hidden;
|
300
|
+
*zoom: 1;
|
301
|
+
}
|
302
|
+
#message > header .metadata {
|
303
|
+
overflow: hidden;
|
304
|
+
*zoom: 1;
|
305
|
+
padding: 0.5em;
|
306
|
+
padding-top: 0;
|
307
|
+
}
|
308
|
+
#message > header .metadata dt, #message > header .metadata dd {
|
309
|
+
padding: 0.25em;
|
310
|
+
}
|
311
|
+
#message > header .metadata dt {
|
312
|
+
float: left;
|
313
|
+
clear: left;
|
314
|
+
width: 8em;
|
315
|
+
margin-right: 0.5em;
|
316
|
+
text-align: right;
|
317
|
+
font-weight: bold;
|
318
|
+
color: #666666;
|
319
|
+
text-shadow: 0 1px 0 white;
|
320
|
+
}
|
321
|
+
#message > header .metadata dd.subject {
|
322
|
+
font-weight: bold;
|
323
|
+
}
|
324
|
+
#message > header .metadata .attachments {
|
325
|
+
display: none;
|
326
|
+
}
|
327
|
+
#message > header .metadata .attachments ul {
|
328
|
+
display: inline;
|
329
|
+
}
|
330
|
+
#message > header .metadata .attachments ul li {
|
331
|
+
display: -moz-inline-box;
|
332
|
+
-moz-box-orient: vertical;
|
333
|
+
display: inline-block;
|
334
|
+
vertical-align: middle;
|
335
|
+
*vertical-align: auto;
|
336
|
+
margin-right: 0.5em;
|
337
|
+
}
|
338
|
+
#message > header .metadata .attachments ul li {
|
339
|
+
*display: inline;
|
340
|
+
}
|
341
|
+
#message > header .views ul {
|
342
|
+
padding: 0 0.5em;
|
343
|
+
border-bottom: 1px solid #cccccc;
|
344
|
+
}
|
345
|
+
#message > header .views .tab {
|
346
|
+
display: -moz-inline-box;
|
347
|
+
-moz-box-orient: vertical;
|
348
|
+
display: inline-block;
|
349
|
+
vertical-align: middle;
|
350
|
+
*vertical-align: auto;
|
351
|
+
}
|
352
|
+
#message > header .views .tab {
|
353
|
+
*display: inline;
|
354
|
+
}
|
355
|
+
#message > header .views .tab a {
|
356
|
+
display: -moz-inline-box;
|
357
|
+
-moz-box-orient: vertical;
|
358
|
+
display: inline-block;
|
359
|
+
vertical-align: middle;
|
360
|
+
*vertical-align: auto;
|
361
|
+
padding: 0.5em;
|
362
|
+
border: 1px solid #cccccc;
|
363
|
+
background: #dddddd;
|
364
|
+
color: #333333;
|
365
|
+
border-width: 1px 1px 0 1px;
|
366
|
+
cursor: pointer;
|
367
|
+
text-shadow: 0 1px 0 #eeeeee;
|
368
|
+
text-decoration: none;
|
369
|
+
}
|
370
|
+
#message > header .views .tab a {
|
371
|
+
*display: inline;
|
372
|
+
}
|
373
|
+
#message > header .views .tab:not(.selected):hover a {
|
374
|
+
background-color: #eeeeee;
|
375
|
+
}
|
376
|
+
#message > header .views .tab.selected a {
|
377
|
+
background: white;
|
378
|
+
color: black;
|
379
|
+
height: 13px;
|
380
|
+
-webkit-box-shadow: 1px 1px 0 #cccccc;
|
381
|
+
-moz-box-shadow: 1px 1px 0 #cccccc;
|
382
|
+
box-shadow: 1px 1px 0 #cccccc;
|
383
|
+
margin-bottom: -2px;
|
384
|
+
cursor: default;
|
385
|
+
}
|
386
|
+
#message > header .views .action {
|
387
|
+
display: -moz-inline-box;
|
388
|
+
-moz-box-orient: vertical;
|
389
|
+
display: inline-block;
|
390
|
+
vertical-align: middle;
|
391
|
+
*vertical-align: auto;
|
392
|
+
float: right;
|
393
|
+
margin: 0 0.25em;
|
394
|
+
}
|
395
|
+
#message > header .views .action {
|
396
|
+
*display: inline;
|
397
|
+
}
|
335
398
|
|
336
399
|
.fractal-analysis {
|
337
|
-
margin: 12px 0;
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
400
|
+
margin: 12px 0;
|
401
|
+
}
|
402
|
+
.fractal-analysis .report-intro {
|
403
|
+
font-weight: bold;
|
404
|
+
}
|
405
|
+
.fractal-analysis .report-intro.valid {
|
406
|
+
color: #009900;
|
407
|
+
}
|
408
|
+
.fractal-analysis .report-intro.invalid {
|
409
|
+
color: #cc3333;
|
410
|
+
}
|
411
|
+
.fractal-analysis code {
|
412
|
+
font-family: Monaco, "Courier New", Courier, monospace;
|
413
|
+
background-color: #f8f8ff;
|
414
|
+
color: #444444;
|
415
|
+
padding: 0 0.2em;
|
416
|
+
border: 1px solid #dedede;
|
417
|
+
}
|
418
|
+
.fractal-analysis ul {
|
419
|
+
margin: 1em 0 1em 1em;
|
420
|
+
list-style-type: square;
|
421
|
+
}
|
422
|
+
.fractal-analysis ol {
|
423
|
+
margin: 1em 0 1em 2em;
|
424
|
+
list-style-type: decimal;
|
425
|
+
}
|
426
|
+
.fractal-analysis ul li, .fractal-analysis ol li {
|
427
|
+
display: list-item;
|
428
|
+
margin: 0.5em 0 0.5em 1em;
|
429
|
+
}
|
430
|
+
.fractal-analysis .error-intro strong {
|
431
|
+
font-weight: bold;
|
432
|
+
}
|
433
|
+
.fractal-analysis .unsupported-clients dt {
|
434
|
+
padding-left: 1em;
|
435
|
+
}
|
436
|
+
.fractal-analysis .unsupported-clients dd {
|
437
|
+
padding-left: 2em;
|
438
|
+
}
|
439
|
+
.fractal-analysis .unsupported-clients dd ul li {
|
440
|
+
display: list-item;
|
441
|
+
}
|
367
442
|
|
368
443
|
iframe {
|
369
|
-
display: -moz-box;
|
370
444
|
display: -webkit-box;
|
445
|
+
display: -moz-box;
|
371
446
|
display: -ms-box;
|
372
447
|
display: box;
|
373
|
-
-moz-box-flex: 1;
|
374
448
|
-webkit-box-flex: 1;
|
449
|
+
-moz-box-flex: 1;
|
375
450
|
-ms-box-flex: 1;
|
376
451
|
box-flex: 1;
|
377
|
-
background: white;
|
452
|
+
background: white;
|
453
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mailcatcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: '0
|
37
|
+
version: '1.0'
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: '0
|
45
|
+
version: '1.0'
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: haml
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -92,16 +92,13 @@ dependencies:
|
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '1.2'
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
95
|
+
name: sqlite3
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
99
99
|
- - ~>
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: '
|
102
|
-
- - ! '>='
|
103
|
-
- !ruby/object:Gem::Version
|
104
|
-
version: 0.2.1
|
101
|
+
version: '1.3'
|
105
102
|
type: :runtime
|
106
103
|
prerelease: false
|
107
104
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -109,74 +106,71 @@ dependencies:
|
|
109
106
|
requirements:
|
110
107
|
- - ~>
|
111
108
|
- !ruby/object:Gem::Version
|
112
|
-
version: '
|
113
|
-
- - ! '>='
|
114
|
-
- !ruby/object:Gem::Version
|
115
|
-
version: 0.2.1
|
109
|
+
version: '1.3'
|
116
110
|
- !ruby/object:Gem::Dependency
|
117
|
-
name:
|
111
|
+
name: thin
|
118
112
|
requirement: !ruby/object:Gem::Requirement
|
119
113
|
none: false
|
120
114
|
requirements:
|
121
|
-
- -
|
115
|
+
- - ! '>='
|
122
116
|
- !ruby/object:Gem::Version
|
123
|
-
version: '
|
117
|
+
version: '0'
|
124
118
|
type: :runtime
|
125
119
|
prerelease: false
|
126
120
|
version_requirements: !ruby/object:Gem::Requirement
|
127
121
|
none: false
|
128
122
|
requirements:
|
129
|
-
- -
|
123
|
+
- - ! '>='
|
130
124
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
125
|
+
version: '0'
|
132
126
|
- !ruby/object:Gem::Dependency
|
133
|
-
name:
|
127
|
+
name: skinny
|
134
128
|
requirement: !ruby/object:Gem::Requirement
|
135
129
|
none: false
|
136
130
|
requirements:
|
137
|
-
- -
|
131
|
+
- - ! '>='
|
138
132
|
- !ruby/object:Gem::Version
|
139
|
-
version: '
|
133
|
+
version: '0'
|
140
134
|
type: :runtime
|
141
135
|
prerelease: false
|
142
136
|
version_requirements: !ruby/object:Gem::Requirement
|
143
137
|
none: false
|
144
138
|
requirements:
|
145
|
-
- -
|
139
|
+
- - ! '>='
|
146
140
|
- !ruby/object:Gem::Version
|
147
|
-
version: '
|
141
|
+
version: '0'
|
148
142
|
- !ruby/object:Gem::Dependency
|
149
143
|
name: coffee-script
|
150
144
|
requirement: !ruby/object:Gem::Requirement
|
151
145
|
none: false
|
152
146
|
requirements:
|
153
|
-
- -
|
147
|
+
- - ! '>='
|
154
148
|
- !ruby/object:Gem::Version
|
155
|
-
version: '
|
149
|
+
version: '0'
|
156
150
|
type: :development
|
157
151
|
prerelease: false
|
158
152
|
version_requirements: !ruby/object:Gem::Requirement
|
159
153
|
none: false
|
160
154
|
requirements:
|
161
|
-
- -
|
155
|
+
- - ! '>='
|
162
156
|
- !ruby/object:Gem::Version
|
163
|
-
version: '
|
157
|
+
version: '0'
|
164
158
|
- !ruby/object:Gem::Dependency
|
165
159
|
name: compass
|
166
160
|
requirement: !ruby/object:Gem::Requirement
|
167
161
|
none: false
|
168
162
|
requirements:
|
169
|
-
- -
|
163
|
+
- - ! '>='
|
170
164
|
- !ruby/object:Gem::Version
|
171
|
-
version: 0
|
165
|
+
version: '0'
|
172
166
|
type: :development
|
173
167
|
prerelease: false
|
174
168
|
version_requirements: !ruby/object:Gem::Requirement
|
175
169
|
none: false
|
176
170
|
requirements:
|
177
|
-
- -
|
171
|
+
- - ! '>='
|
178
172
|
- !ruby/object:Gem::Version
|
179
|
-
version: 0
|
173
|
+
version: '0'
|
180
174
|
- !ruby/object:Gem::Dependency
|
181
175
|
name: rake
|
182
176
|
requirement: !ruby/object:Gem::Requirement
|
@@ -214,17 +208,17 @@ dependencies:
|
|
214
208
|
requirement: !ruby/object:Gem::Requirement
|
215
209
|
none: false
|
216
210
|
requirements:
|
217
|
-
- -
|
211
|
+
- - ! '>='
|
218
212
|
- !ruby/object:Gem::Version
|
219
|
-
version: '
|
213
|
+
version: '0'
|
220
214
|
type: :development
|
221
215
|
prerelease: false
|
222
216
|
version_requirements: !ruby/object:Gem::Requirement
|
223
217
|
none: false
|
224
218
|
requirements:
|
225
|
-
- -
|
219
|
+
- - ! '>='
|
226
220
|
- !ruby/object:Gem::Version
|
227
|
-
version: '
|
221
|
+
version: '0'
|
228
222
|
description: ! " MailCatcher runs a super simple SMTP server which catches any\n
|
229
223
|
\ message sent to it to display in a web interface. Run\n mailcatcher, set
|
230
224
|
your favourite app to deliver to\n smtp://127.0.0.1:1025 instead of your default
|
@@ -240,15 +234,16 @@ extra_rdoc_files:
|
|
240
234
|
files:
|
241
235
|
- README.md
|
242
236
|
- LICENSE
|
243
|
-
- VERSION
|
244
237
|
- bin/catchmail
|
245
238
|
- bin/mailcatcher
|
246
239
|
- lib/mail_catcher/events.rb
|
247
240
|
- lib/mail_catcher/growl.rb
|
248
241
|
- lib/mail_catcher/mail.rb
|
249
242
|
- lib/mail_catcher/smtp.rb
|
243
|
+
- lib/mail_catcher/version.rb
|
250
244
|
- lib/mail_catcher/web.rb
|
251
245
|
- lib/mail_catcher.rb
|
246
|
+
- public/favicon.ico
|
252
247
|
- public/images/logo.png
|
253
248
|
- public/images/logo_large.png
|
254
249
|
- public/javascripts/application.js
|
@@ -286,3 +281,4 @@ signing_key:
|
|
286
281
|
specification_version: 3
|
287
282
|
summary: Runs an SMTP server, catches and displays email in a web interface.
|
288
283
|
test_files: []
|
284
|
+
has_rdoc:
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.5.8
|