mailcatcher 0.5.12 → 0.8.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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/README.md +77 -42
- data/bin/catchmail +24 -2
- data/bin/mailcatcher +2 -0
- data/lib/mail_catcher/bus.rb +7 -0
- data/lib/mail_catcher/mail.rb +47 -24
- data/lib/mail_catcher/smtp.rb +23 -12
- data/lib/mail_catcher/version.rb +3 -1
- data/lib/mail_catcher/web/application.rb +179 -0
- data/lib/mail_catcher/web.rb +18 -137
- data/lib/mail_catcher.rb +117 -67
- data/lib/mailcatcher.rb +5 -0
- data/public/assets/logo.png +0 -0
- data/public/assets/logo_2x.png +0 -0
- data/public/assets/logo_large.png +0 -0
- data/public/assets/mailcatcher.css +1 -0
- data/public/assets/mailcatcher.js +5 -0
- data/public/favicon.ico +0 -0
- data/views/404.erb +6 -0
- data/views/index.erb +70 -0
- data.tar.gz.sig +0 -0
- metadata +174 -88
- metadata.gz.sig +0 -0
- data/lib/mail_catcher/events.rb +0 -5
- data/lib/mail_catcher/growl.rb +0 -16
- data/public/images/logo.png +0 -0
- data/public/images/logo_large.png +0 -0
- data/public/javascripts/application.js +0 -408
- data/public/javascripts/date.js +0 -104
- data/public/javascripts/flexie.min.js +0 -36
- data/public/javascripts/jquery.js +0 -6883
- data/public/javascripts/keymaster.min.js +0 -4
- data/public/javascripts/modernizr.js +0 -3
- data/public/javascripts/xslt-3.2.js +0 -1
- data/public/stylesheets/analysis.xsl +0 -33
- data/public/stylesheets/application.css +0 -375
- data/views/index.haml +0 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 398459f93087b0066f8e2f8fd34781c2db1c6c3a8b2e13183a5cc425765f3347
|
4
|
+
data.tar.gz: 167623ed70957092aa6609d872cec9098f4d92184033df8b1cda9f83a2d8a31d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65dcc3d2041456601dfd69f4cb522817522b7243cc1ac09b2e08c3905693cf99063aad8f262154577d2ad3ea94836c27cd0be7f1186cadf2abab7f968b7778e4
|
7
|
+
data.tar.gz: 71bbe2396c4ba43857d346a5ee93269e314ac2cf4f694babfaf7a79c96f4d6c9f86d1df76f66b76e4e8df272371963c94418f07ce5cc2a9d204a13a0f4b3ea7b
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.md
CHANGED
@@ -4,65 +4,119 @@ Catches mail and serves it through a dream.
|
|
4
4
|
|
5
5
|
MailCatcher runs a super simple SMTP server which catches any message sent to it to display in a web interface. Run mailcatcher, set your favourite app to deliver to smtp://127.0.0.1:1025 instead of your default SMTP server, then check out http://127.0.0.1:1080 to see the mail that's arrived so far.
|
6
6
|
|
7
|
-

|
8
8
|
|
9
9
|
## Features
|
10
10
|
|
11
11
|
* Catches all mail and stores it for display.
|
12
12
|
* Shows HTML, Plain Text and Source version of messages, as applicable.
|
13
|
-
* Rewrites HTML enabling display of embedded, inline images/etc and
|
14
|
-
* Can send HTML for analysis by [Fractal][fractal].
|
13
|
+
* Rewrites HTML enabling display of embedded, inline images/etc and opens links in a new window.
|
15
14
|
* Lists attachments and allows separate downloading of parts.
|
16
15
|
* Download original email to view in your native mail client(s).
|
17
16
|
* Command line options to override the default SMTP/HTTP IP and port settings.
|
18
17
|
* Mail appears instantly if your browser supports [WebSockets][websockets], otherwise updates every thirty seconds.
|
19
|
-
*
|
20
|
-
*
|
21
|
-
* Sendmail-analogue command, `catchmail`, makes [using mailcatcher from PHP][withphp] a lot easier.
|
22
|
-
* Written super-simply in EventMachine, easy to dig in and change.
|
18
|
+
* Runs as a daemon in the background, optionally in foreground.
|
19
|
+
* Sendmail-analogue command, `catchmail`, makes using mailcatcher from PHP a lot easier.
|
23
20
|
* Keyboard navigation between messages
|
24
21
|
|
25
22
|
## How
|
26
23
|
|
27
24
|
1. `gem install mailcatcher`
|
28
25
|
2. `mailcatcher`
|
29
|
-
3. Go to http://
|
30
|
-
4. Send mail through smtp://
|
26
|
+
3. Go to http://127.0.0.1:1080/
|
27
|
+
4. Send mail through smtp://127.0.0.1:1025
|
31
28
|
|
32
|
-
|
29
|
+
### Command Line Options
|
30
|
+
|
31
|
+
Use `mailcatcher --help` to see the command line options.
|
32
|
+
|
33
|
+
```
|
34
|
+
Usage: mailcatcher [options]
|
35
|
+
|
36
|
+
MailCatcher v0.8.0
|
37
|
+
|
38
|
+
--ip IP Set the ip address of both servers
|
39
|
+
--smtp-ip IP Set the ip address of the smtp server
|
40
|
+
--smtp-port PORT Set the port of the smtp server
|
41
|
+
--http-ip IP Set the ip address of the http server
|
42
|
+
--http-port PORT Set the port address of the http server
|
43
|
+
--messages-limit COUNT Only keep up to COUNT most recent messages
|
44
|
+
--http-path PATH Add a prefix to all HTTP paths
|
45
|
+
--no-quit Don't allow quitting the process
|
46
|
+
-f, --foreground Run in the foreground
|
47
|
+
-b, --browse Open web browser
|
48
|
+
-v, --verbose Be more verbose
|
49
|
+
-h, --help Display this help information
|
50
|
+
--version Display the current version
|
51
|
+
```
|
52
|
+
|
53
|
+
### Ruby
|
54
|
+
|
55
|
+
If you have trouble with the setup commands, make sure you have [Ruby installed](https://www.ruby-lang.org/en/documentation/installation/):
|
56
|
+
|
57
|
+
```
|
58
|
+
ruby -v
|
59
|
+
gem environment
|
60
|
+
```
|
61
|
+
|
62
|
+
You might need to install build tools for some of the gem dependencies. On Debian or Ubuntu, `apt install build-essential`. On macOS, `xcode-select --install`.
|
63
|
+
|
64
|
+
If you encounter issues installing [thin](https://rubygems.org/gems/thin), try:
|
65
|
+
|
66
|
+
```
|
67
|
+
gem install thin -v 1.5.1 -- --with-cflags="-Wno-error=implicit-function-declaration"
|
68
|
+
```
|
33
69
|
|
34
70
|
### Bundler
|
35
71
|
|
36
|
-
Please don't put mailcatcher into your Gemfile. It will conflict with your
|
72
|
+
Please don't put mailcatcher into your Gemfile. It will conflict with your application's gems at some point.
|
37
73
|
|
38
|
-
Instead, pop a note in your README stating you use mailcatcher
|
74
|
+
Instead, pop a note in your README stating you use mailcatcher, and to run `gem install mailcatcher` then `mailcatcher` to get started.
|
39
75
|
|
40
76
|
### RVM
|
41
77
|
|
42
|
-
Under RVM your mailcatcher command may only be available under the ruby you install mailcatcher into. To prevent this, and to prevent gem conflicts, install mailcatcher into a dedicated gemset
|
78
|
+
Under RVM your mailcatcher command may only be available under the ruby you install mailcatcher into. To prevent this, and to prevent gem conflicts, install mailcatcher into a dedicated gemset with a wrapper script:
|
43
79
|
|
44
80
|
rvm default@mailcatcher --create do gem install mailcatcher
|
45
|
-
rvm
|
81
|
+
ln -s "$(rvm default@mailcatcher do rvm wrapper show mailcatcher)" "$rvm_bin_path/"
|
46
82
|
|
47
83
|
### Rails
|
48
84
|
|
49
|
-
To set up your rails app, I recommend adding this to your `
|
85
|
+
To set up your rails app, I recommend adding this to your `environments/development.rb`:
|
50
86
|
|
51
87
|
config.action_mailer.delivery_method = :smtp
|
52
|
-
config.action_mailer.smtp_settings = { :address =>
|
88
|
+
config.action_mailer.smtp_settings = { :address => '127.0.0.1', :port => 1025 }
|
89
|
+
config.action_mailer.raise_delivery_errors = false
|
53
90
|
|
54
91
|
### PHP
|
55
92
|
|
56
|
-
For projects using PHP, or PHP frameworks and application platforms like Drupal, you can set [PHP's mail configuration](
|
93
|
+
For projects using PHP, or PHP frameworks and application platforms like Drupal, you can set [PHP's mail configuration](https://www.php.net/manual/en/mail.configuration.php) in your [php.ini](https://www.php.net/manual/en/configuration.file.php) to send via MailCatcher with:
|
57
94
|
|
58
|
-
sendmail_path = /usr/bin/env catchmail
|
95
|
+
sendmail_path = /usr/bin/env catchmail -f some@from.address
|
59
96
|
|
60
|
-
You can do this in
|
97
|
+
You can do this in your [Apache configuration](https://www.php.net/manual/en/configuration.changes.php) like so:
|
61
98
|
|
62
|
-
|
99
|
+
php_admin_value sendmail_path "/usr/bin/env catchmail -f some@from.address"
|
63
100
|
|
64
101
|
If you've installed via RVM this probably won't work unless you've manually added your RVM bin paths to your system environment's PATH. In that case, run `which catchmail` and put that path into the `sendmail_path` directive above instead of `/usr/bin/env catchmail`.
|
65
102
|
|
103
|
+
If starting `mailcatcher` on alternative SMTP IP and/or port with parameters like `--smtp-ip 192.168.0.1 --smtp-port 10025`, add the same parameters to your `catchmail` command:
|
104
|
+
|
105
|
+
sendmail_path = /usr/bin/env catchmail --smtp-ip 192.160.0.1 --smtp-port 10025 -f some@from.address
|
106
|
+
|
107
|
+
### Django
|
108
|
+
|
109
|
+
For use in Django, add the following configuration to your projects' settings.py
|
110
|
+
|
111
|
+
```python
|
112
|
+
if DEBUG:
|
113
|
+
EMAIL_HOST = '127.0.0.1'
|
114
|
+
EMAIL_HOST_USER = ''
|
115
|
+
EMAIL_HOST_PASSWORD = ''
|
116
|
+
EMAIL_PORT = 1025
|
117
|
+
EMAIL_USE_TLS = False
|
118
|
+
```
|
119
|
+
|
66
120
|
### API
|
67
121
|
|
68
122
|
A fairly RESTful URL schema means you can download a list of messages in JSON from `/messages`, each message's metadata with `/messages/:id.json`, and then the pertinent parts with `/messages/:id.html` and `/messages/:id.plain` for the default HTML and plain text version, `/messages/:id/:cid` for individual attachments by CID, or the whole message with `/messages/:id.source`.
|
@@ -70,41 +124,22 @@ A fairly RESTful URL schema means you can download a list of messages in JSON fr
|
|
70
124
|
## Caveats
|
71
125
|
|
72
126
|
* Mail processing is fairly basic but easily modified. If something doesn't work for you, fork and fix it or [file an issue][mailcatcher-issues] and let me know. Include the whole message you're having problems with.
|
73
|
-
*
|
74
|
-
|
75
|
-
## TODO
|
76
|
-
|
77
|
-
* Add mail delivery on request, optionally multiple times.
|
78
|
-
* Better Growl support in MacRuby and RubyCocoa with click notifications which takes you to the received message.
|
79
|
-
* An API-compatible nodejs version, for fun and profit (and non-ruby npm users).
|
80
|
-
* Test suite.
|
81
|
-
* Compatibility testing against CampaignMonitor's [design guidelines](http://www.campaignmonitor.com/design-guidelines/) and [CSS support matrix](http://www.campaignmonitor.com/design-guidelines/).
|
82
|
-
* Forward mail to rendering service, maybe CampaignMonitor?
|
83
|
-
* Package as an app? Native interfaces? HotCocoa?
|
127
|
+
* Encodings are difficult. MailCatcher does not completely support utf-8 straight over the wire, you must use a mail library which encodes things properly based on SMTP server capabilities.
|
84
128
|
|
85
129
|
## Thanks
|
86
130
|
|
87
131
|
MailCatcher is just a mishmash of other people's hard work. Thank you so much to the people who have built the wonderful guts on which this project relies.
|
88
132
|
|
89
|
-
Thanks also to [The Frontier Group][tfg] for giving me the idea, being great guinea pigs and letting me steal pieces of time to keep the project alive.
|
90
|
-
|
91
133
|
## Donations
|
92
134
|
|
93
135
|
I work on MailCatcher mostly in my own spare time. If you've found Mailcatcher useful and would like to help feed me and fund continued development and new features, please [donate via PayPal][donate]. If you'd like a specific feature added to MailCatcher and are willing to pay for it, please [email me](mailto:sj26@sj26.com).
|
94
136
|
|
95
137
|
## License
|
96
138
|
|
97
|
-
Copyright © 2010-
|
98
|
-
|
99
|
-
## Dreams
|
100
|
-
|
101
|
-
For dream catching, try [this](http://goo.gl/kgbh). OR [THIS](http://www.nyanicorn.com), OMG.
|
139
|
+
Copyright © 2010-2019 Samuel Cochran (sj26@sj26.com). Released under the MIT License, see [LICENSE][license] for details.
|
102
140
|
|
103
141
|
[donate]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=522WUPLRWUSKE
|
104
|
-
[fractal]: http://getfractal.com
|
105
142
|
[license]: https://github.com/sj26/mailcatcher/blob/master/LICENSE
|
106
143
|
[mailcatcher-github]: https://github.com/sj26/mailcatcher
|
107
144
|
[mailcatcher-issues]: https://github.com/sj26/mailcatcher/issues
|
108
|
-
[
|
109
|
-
[websockets]: http://www.whatwg.org/specs/web-socket-protocol/
|
110
|
-
[withphp]: http://webschuur.com/publications/blogs/2011-05-29-catchmail_for_drupal_and_other_phpapplications_the_simple_version
|
145
|
+
[websockets]: https://tools.ietf.org/html/rfc6455
|
data/bin/catchmail
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
begin
|
4
5
|
require 'mail'
|
@@ -13,7 +14,7 @@ options = {:smtp_ip => '127.0.0.1', :smtp_port => 1025}
|
|
13
14
|
|
14
15
|
OptionParser.new do |parser|
|
15
16
|
parser.banner = <<-BANNER.gsub /^ +/, ""
|
16
|
-
Usage: catchmail [options]
|
17
|
+
Usage: catchmail [options] [recipient ...]
|
17
18
|
sendmail-like interface to forward mail to MailCatcher.
|
18
19
|
BANNER
|
19
20
|
|
@@ -33,6 +34,17 @@ OptionParser.new do |parser|
|
|
33
34
|
options[:from] = from
|
34
35
|
end
|
35
36
|
|
37
|
+
parser.on('-oi', 'Ignored option -oi') do |ignored|
|
38
|
+
end
|
39
|
+
parser.on('-t', 'Ignored option -t') do |ignored|
|
40
|
+
end
|
41
|
+
parser.on('-q', 'Ignored option -q') do |ignored|
|
42
|
+
end
|
43
|
+
|
44
|
+
parser.on('-x', '--no-exit', 'Can\'t exit from the application') do
|
45
|
+
options[:no_exit] = true
|
46
|
+
end
|
47
|
+
|
36
48
|
parser.on('-h', '--help', 'Display this help information') do
|
37
49
|
puts parser
|
38
50
|
exit!
|
@@ -45,6 +57,16 @@ Mail.defaults do
|
|
45
57
|
:port => options[:smtp_port]
|
46
58
|
end
|
47
59
|
|
48
|
-
message = Mail.new
|
60
|
+
message = Mail.new($stdin.read)
|
61
|
+
|
49
62
|
message.return_path = options[:from] if options[:from]
|
63
|
+
|
64
|
+
ARGV.each do |recipient|
|
65
|
+
if message.to.nil?
|
66
|
+
message.to = recipient
|
67
|
+
else
|
68
|
+
message.to << recipient
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
50
72
|
message.deliver
|
data/bin/mailcatcher
CHANGED
data/lib/mail_catcher/mail.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "eventmachine"
|
4
|
+
require "json"
|
5
|
+
require "mail"
|
6
|
+
require "sqlite3"
|
5
7
|
|
6
8
|
module MailCatcher::Mail extend self
|
7
9
|
def db
|
8
10
|
@__db ||= begin
|
9
|
-
SQLite3::Database.new(
|
11
|
+
SQLite3::Database.new(":memory:", :type_translation => true).tap do |db|
|
10
12
|
db.execute(<<-SQL)
|
11
13
|
CREATE TABLE message (
|
12
14
|
id INTEGER PRIMARY KEY ASC,
|
@@ -30,9 +32,11 @@ module MailCatcher::Mail extend self
|
|
30
32
|
charset TEXT,
|
31
33
|
body BLOB,
|
32
34
|
size INTEGER,
|
33
|
-
created_at DATETIME DEFAULT CURRENT_DATETIME
|
35
|
+
created_at DATETIME DEFAULT CURRENT_DATETIME,
|
36
|
+
FOREIGN KEY (message_id) REFERENCES message (id) ON DELETE CASCADE
|
34
37
|
)
|
35
38
|
SQL
|
39
|
+
db.execute("PRAGMA foreign_keys = ON")
|
36
40
|
end
|
37
41
|
end
|
38
42
|
end
|
@@ -41,7 +45,7 @@ module MailCatcher::Mail extend self
|
|
41
45
|
@add_message_query ||= db.prepare("INSERT INTO message (sender, recipients, subject, source, type, size, created_at) VALUES (?, ?, ?, ?, ?, ?, datetime('now'))")
|
42
46
|
|
43
47
|
mail = Mail.new(message[:source])
|
44
|
-
@add_message_query.execute(message[:sender], message[:recipients]
|
48
|
+
@add_message_query.execute(message[:sender], JSON.generate(message[:recipients]), mail.subject, message[:source], mail.mime_type || "text/plain", message[:source].length)
|
45
49
|
message_id = db.last_insert_row_id
|
46
50
|
parts = mail.all_parts
|
47
51
|
parts = [mail] if parts.empty?
|
@@ -49,12 +53,12 @@ module MailCatcher::Mail extend self
|
|
49
53
|
body = part.body.to_s
|
50
54
|
# Only parts have CIDs, not mail
|
51
55
|
cid = part.cid if part.respond_to? :cid
|
52
|
-
add_message_part(message_id, cid, part.mime_type ||
|
56
|
+
add_message_part(message_id, cid, part.mime_type || "text/plain", part.attachment? ? 1 : 0, part.filename, part.charset, body, body.length)
|
53
57
|
end
|
54
58
|
|
55
59
|
EventMachine.next_tick do
|
56
60
|
message = MailCatcher::Mail.message message_id
|
57
|
-
MailCatcher::
|
61
|
+
MailCatcher::Bus.push(type: "add", message: message)
|
58
62
|
end
|
59
63
|
end
|
60
64
|
|
@@ -69,25 +73,31 @@ module MailCatcher::Mail extend self
|
|
69
73
|
end
|
70
74
|
|
71
75
|
def messages
|
72
|
-
@messages_query ||= db.prepare "SELECT id, sender, recipients, subject, size, created_at FROM message ORDER BY created_at
|
76
|
+
@messages_query ||= db.prepare "SELECT id, sender, recipients, subject, size, created_at FROM message ORDER BY created_at, id ASC"
|
73
77
|
@messages_query.execute.map do |row|
|
74
78
|
Hash[row.fields.zip(row)].tap do |message|
|
75
|
-
message["recipients"] &&=
|
79
|
+
message["recipients"] &&= JSON.parse(message["recipients"])
|
76
80
|
end
|
77
81
|
end
|
78
82
|
end
|
79
83
|
|
80
84
|
def message(id)
|
81
|
-
@message_query ||= db.prepare "SELECT
|
85
|
+
@message_query ||= db.prepare "SELECT id, sender, recipients, subject, size, type, created_at FROM message WHERE id = ? LIMIT 1"
|
82
86
|
row = @message_query.execute(id).next
|
83
87
|
row && Hash[row.fields.zip(row)].tap do |message|
|
84
|
-
message["recipients"] &&=
|
88
|
+
message["recipients"] &&= JSON.parse(message["recipients"])
|
85
89
|
end
|
86
90
|
end
|
87
91
|
|
92
|
+
def message_source(id)
|
93
|
+
@message_source_query ||= db.prepare "SELECT source FROM message WHERE id = ? LIMIT 1"
|
94
|
+
row = @message_source_query.execute(id).next
|
95
|
+
row && row.first
|
96
|
+
end
|
97
|
+
|
88
98
|
def message_has_html?(id)
|
89
99
|
@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) || [
|
100
|
+
(!!@message_has_html_query.execute(id).next) || ["text/html", "application/xhtml+xml"].include?(message(id)["type"])
|
91
101
|
end
|
92
102
|
|
93
103
|
def message_has_plain?(id)
|
@@ -126,7 +136,7 @@ module MailCatcher::Mail extend self
|
|
126
136
|
part ||= message_part_type(message_id, "application/xhtml+xml")
|
127
137
|
part ||= begin
|
128
138
|
message = message(message_id)
|
129
|
-
message if message
|
139
|
+
message if message and ["text/html", "application/xhtml+xml"].include? message["type"]
|
130
140
|
end
|
131
141
|
end
|
132
142
|
|
@@ -135,7 +145,7 @@ module MailCatcher::Mail extend self
|
|
135
145
|
end
|
136
146
|
|
137
147
|
def message_part_cid(message_id, cid)
|
138
|
-
@message_part_cid_query ||= db.prepare
|
148
|
+
@message_part_cid_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ?"
|
139
149
|
@message_part_cid_query.execute(message_id).map do |row|
|
140
150
|
Hash[row.fields.zip(row)]
|
141
151
|
end.find do |part|
|
@@ -144,17 +154,30 @@ module MailCatcher::Mail extend self
|
|
144
154
|
end
|
145
155
|
|
146
156
|
def delete!
|
147
|
-
@
|
148
|
-
@
|
157
|
+
@delete_all_messages_query ||= db.prepare "DELETE FROM message"
|
158
|
+
@delete_all_messages_query.execute
|
149
159
|
|
150
|
-
|
151
|
-
|
160
|
+
EventMachine.next_tick do
|
161
|
+
MailCatcher::Bus.push(type: "clear")
|
162
|
+
end
|
152
163
|
end
|
153
164
|
|
154
165
|
def delete_message!(message_id)
|
155
|
-
@delete_messages_query ||= db.prepare
|
156
|
-
@
|
157
|
-
|
158
|
-
|
166
|
+
@delete_messages_query ||= db.prepare "DELETE FROM message WHERE id = ?"
|
167
|
+
@delete_messages_query.execute(message_id)
|
168
|
+
|
169
|
+
EventMachine.next_tick do
|
170
|
+
MailCatcher::Bus.push(type: "remove", id: message_id)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def delete_older_messages!(count = MailCatcher.options[:messages_limit])
|
175
|
+
return if count.nil?
|
176
|
+
@older_messages_query ||= db.prepare "SELECT id FROM message WHERE id NOT IN (SELECT id FROM message ORDER BY created_at DESC LIMIT ?)"
|
177
|
+
@older_messages_query.execute(count).map do |row|
|
178
|
+
Hash[row.fields.zip(row)]
|
179
|
+
end.each do |message|
|
180
|
+
delete_message!(message["id"])
|
181
|
+
end
|
159
182
|
end
|
160
183
|
end
|
data/lib/mail_catcher/smtp.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "eventmachine"
|
4
|
+
|
5
|
+
require "mail_catcher/mail"
|
2
6
|
|
3
7
|
class MailCatcher::Smtp < EventMachine::Protocols::SmtpServer
|
4
8
|
# We override EM's mail from processing to allow multiple mail-from commands
|
5
|
-
# per [RFC 2821](
|
9
|
+
# per [RFC 2821](https://tools.ietf.org/html/rfc2821#section-4.1.1.2)
|
6
10
|
def process_mail_from sender
|
7
11
|
if @state.include? :mail_from
|
8
12
|
@state -= [:mail_from, :rcpt, :data]
|
13
|
+
|
9
14
|
receive_reset
|
10
15
|
end
|
11
16
|
|
@@ -18,38 +23,44 @@ class MailCatcher::Smtp < EventMachine::Protocols::SmtpServer
|
|
18
23
|
|
19
24
|
def receive_reset
|
20
25
|
@current_message = nil
|
26
|
+
|
21
27
|
true
|
22
28
|
end
|
23
29
|
|
24
30
|
def receive_sender(sender)
|
31
|
+
# EventMachine SMTP advertises size extensions [https://tools.ietf.org/html/rfc1870]
|
32
|
+
# so strip potential " SIZE=..." suffixes from senders
|
33
|
+
sender = $` if sender =~ / SIZE=\d+\z/
|
34
|
+
|
25
35
|
current_message[:sender] = sender
|
36
|
+
|
26
37
|
true
|
27
38
|
end
|
28
39
|
|
29
40
|
def receive_recipient(recipient)
|
30
41
|
current_message[:recipients] ||= []
|
31
42
|
current_message[:recipients] << recipient
|
43
|
+
|
32
44
|
true
|
33
45
|
end
|
34
46
|
|
35
47
|
def receive_data_chunk(lines)
|
36
|
-
current_message[:source] ||= ""
|
37
|
-
|
48
|
+
current_message[:source] ||= +""
|
49
|
+
|
50
|
+
lines.each do |line|
|
51
|
+
current_message[:source] << line << "\r\n"
|
52
|
+
end
|
53
|
+
|
38
54
|
true
|
39
55
|
end
|
40
56
|
|
41
57
|
def receive_message
|
42
58
|
MailCatcher::Mail.add_message current_message
|
59
|
+
MailCatcher::Mail.delete_older_messages!
|
43
60
|
puts "==> SMTP: Received message from '#{current_message[:sender]}' (#{current_message[:source].length} bytes)"
|
44
61
|
true
|
45
|
-
rescue
|
46
|
-
|
47
|
-
puts " Exception: #{$!}"
|
48
|
-
puts " Backtrace:"
|
49
|
-
$!.backtrace.each do |line|
|
50
|
-
puts " #{line}"
|
51
|
-
end
|
52
|
-
puts " Please submit this as an issue at http://github.com/sj26/mailcatcher/issues"
|
62
|
+
rescue => exception
|
63
|
+
MailCatcher.log_exception("Error receiving message", @current_message, exception)
|
53
64
|
false
|
54
65
|
ensure
|
55
66
|
@current_message = nil
|
data/lib/mail_catcher/version.rb
CHANGED