mailcatcher 0.5.12 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
![MailCatcher screenshot](
|
7
|
+
![MailCatcher screenshot](https://cloud.githubusercontent.com/assets/14028/14093249/4100f904-f598-11e5-936b-e6a396f18e39.png)
|
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