-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
upd: rewrite README.md for new parts of release 2.x
upd: change major release for beiing INCOMPATIBLE for version 1.x up: rewrite example to bei compatible
- Loading branch information
1 parent
1661daf
commit 2484eda
Showing
3 changed files
with
136 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ | |
|
||
MidiSmtpServer is a small and highly customizable ruby SMTP-Server inspired from the work and code written by [Aaron Gough](https://github.com/aarongough) and [Peter Cooper](http://peterc.org/). As a library it is mainly designed to be integrated into your projects as serving a SMTP-Server service. The lib will do nothing with your mail and you have to create your own event functions to handle and operate on incoming mails. We are using this in conjunction with [Mikel Lindsaar](https://github.com/mikel) great Mail component (https://github.com/mikel/mail). Time to run your own SMTP-Server service. | ||
|
||
With version 2.0 the library got a lot of improvements. I suggest everybody using MidiSmtpServer 1.x to switch to 2.x. You may follow the guide (see appendix) how to change your existing code to be compatible with the new release. | ||
|
||
|
||
## Using the library | ||
|
||
|
@@ -12,7 +14,7 @@ require "midi-smtp-server" | |
require "mail" | ||
|
||
# Server class | ||
class MySmtpServer < MidiSmtpServer | ||
class MySmtpd < MidiSmtpServer::Smtpd | ||
|
||
def start | ||
# initialize and do your own initailizations | ||
|
@@ -21,62 +23,33 @@ class MySmtpServer < MidiSmtpServer | |
super | ||
end | ||
|
||
# get event on HELO: | ||
def on_helo_event(helo_data, ctx) | ||
# Output for debug | ||
puts "#{Time.now}: #{ctx[:server][:remote_ip]} on helo event with data:" | ||
puts "[#{helo_data}]..." | ||
end | ||
|
||
# get address send in MAIL FROM: | ||
def on_mail_from_event(mail_from_data, ctx) | ||
# Output for debug | ||
puts "#{Time.now}: #{ctx[:server][:remote_ip]} on mail from event with data:" | ||
puts "[#{mail_from_data}]..." | ||
end | ||
|
||
# get each address send in RCPT TO: | ||
def on_rcpt_to_event(rcpt_to_data, ctx) | ||
# Output for debug | ||
puts "#{Time.now}: #{ctx[:server][:remote_ip]} on rcpt to event with data:" | ||
puts "[#{rcpt_to_data}]..." | ||
end | ||
|
||
# get each message after DATA <message> . | ||
def on_message_data_event(ctx) | ||
# Output for debug | ||
puts "#{Time.now}: #{ctx[:server][:remote_ip]} on message data event with sender:" | ||
puts "[#{ctx[:envelope][:from]}] for recipient(s): [#{ctx[:envelope][:to]}]..." | ||
logger.debug("[#{ctx[:envelope][:from]}] for recipient(s): [#{ctx[:envelope][:to]}]...") | ||
|
||
# Just decode message ones to make sure, that this message ist readable | ||
@mail = Mail.read_from_string(ctx[:message]) | ||
@mail = Mail.read_from_string(ctx[:message][:data]) | ||
|
||
# handle incoming mail, just show the message source | ||
puts @mail.to_s | ||
|
||
logger.debug(@mail.to_s) | ||
end | ||
|
||
end | ||
|
||
# Output for debug | ||
puts "#{Time.now}: Starting MySmtpServer..." | ||
puts "#{Time.now}: Starting MySmtpd..." | ||
|
||
# Create a new server instance listening at all interfaces *:2525 | ||
# and accepting a maximum of 5 simultaneous connections | ||
server = MySmtpServer.new | ||
|
||
# Enable logging | ||
server.audit = true | ||
# and accepting a maximum of 4 simultaneous connections | ||
server = MySmtpd.new | ||
|
||
# Start the server | ||
server.start | ||
|
||
# wait a second | ||
sleep 1 | ||
|
||
# Output for debug | ||
puts "#{Time.now}: Ready for connections" | ||
|
||
# Run on server forever | ||
server.join | ||
|
||
|
@@ -86,22 +59,21 @@ BEGIN { | |
# check to shutdown connection | ||
if server | ||
# Output for debug | ||
puts "#{Time.now}: Shutdown MySmtpServer..." | ||
puts "#{Time.now}: Shutdown MySmtpd..." | ||
# gracefully connections down | ||
server.shutdown | ||
# check once if some connection(s) need(s) more time | ||
sleep 2 unless server.connections == 0 | ||
# stop all threads and connections | ||
server.stop | ||
# Output for debug | ||
puts "#{Time.now}: MySmtpServer stopped!" | ||
end | ||
# Output for debug | ||
puts "#{Time.now}: MySmtpServer down!" | ||
puts "#{Time.now}: MySmtpd down!" | ||
} | ||
} | ||
``` | ||
|
||
|
||
## Installation | ||
|
||
MidiSmtpServer is packaged as a RubyGem so that you can easily install by entering following at your command line: | ||
|
@@ -127,26 +99,27 @@ MidiSmtpServer can be easy customized via subclassing. Simply subclass the `Midi | |
end | ||
|
||
# get event on HELO: | ||
def on_helo_event(helo_data, ctx) | ||
def on_helo_event(ctx, helo_data) | ||
end | ||
|
||
# get address send in MAIL FROM: | ||
# if any value returned, that will be used for ongoing processing | ||
# otherwise the original value will be used | ||
def on_mail_from_event(mail_from_data, ctx) | ||
def on_mail_from_event(ctx, mail_from_data) | ||
end | ||
|
||
# get each address send in RCPT TO: | ||
# if any value returned, that will be used for ongoing processing | ||
# otherwise the original value will be used | ||
def on_rcpt_to_event(rcpt_to_data, ctx) | ||
def on_rcpt_to_event(ctx, rcpt_to_data) | ||
end | ||
|
||
# get each message after DATA <message> . | ||
def on_message_data_event(ctx) | ||
end | ||
``` | ||
|
||
|
||
## Modifying MAIL FROM and RCPT TO addresses | ||
|
||
Since release `1.1.4` the `on_mail_from_event` and `on_rcpt_to_event` allows to return values that should be added to the lists. This is useful if you want to e.g. normalize all incoming addresses. Format defined by RFC for `<path>` as a `MAIL FROM` or `RCPT TO` addresses is: | ||
|
@@ -161,7 +134,7 @@ To make it easier for processing addresses, you are able to normalize them like: | |
|
||
```ruby | ||
# simple rewrite and return value | ||
def on_mail_from_event(mail_from_data, ctx) | ||
def on_mail_from_event(ctx, mail_from_data) | ||
# strip and normalize addresses like: <path> to path | ||
mail_from_data.gsub!(/^\s*<\s*(.*)\s*>\s*$/, '\1') | ||
# we believe in downcased addresses | ||
|
@@ -171,7 +144,7 @@ To make it easier for processing addresses, you are able to normalize them like: | |
end | ||
|
||
# rewrite, process more checks and return value | ||
def on_rcpt_to_event(rcpt_to_data, ctx) | ||
def on_rcpt_to_event(ctx, rcpt_to_data) | ||
# strip and normalize addresses like: <path> to path | ||
rcpt_to_data.gsub!(/^\s*<\s*(.*)\s*>\s*$/, '\1') | ||
# we believe in downcased addresses | ||
|
@@ -183,6 +156,7 @@ To make it easier for processing addresses, you are able to normalize them like: | |
end | ||
``` | ||
|
||
|
||
## Responding with errors on special conditions | ||
|
||
If you return from event class without an exception, the server will respond to client with the appropriate success code, otherwise the client will be noticed about an error. | ||
|
@@ -192,11 +166,11 @@ So you can build SPAM protection, when raising exception while getting `RCPT TO` | |
```ruby | ||
# get each address send in RCPT TO: | ||
def on_rcpt_to_event(rcpt_to_data, ctx) | ||
raise MidiSmtpServer550Exception if rcpt_to_data == "[email protected]" | ||
raise MidiSmtpServer::Smtpd550Exception if rcpt_to_data == "[email protected]" | ||
end | ||
``` | ||
|
||
You are able to use exceptions on any level of events, so for an example you could raise an exception on `on_message_data_event` if you checked attachments for a pdf-document and fail or so on. If you use the defined `MidiSmtpServer???Exception` classes the remote client get's correct SMTP Server results. For logging purpose the default Exception.message is written to log. | ||
You are able to use exceptions on any level of events, so for an example you could raise an exception on `on_message_data_event` if you checked attachments for a pdf-document and fail or so on. If you use the defined `MidiSmtpServer::Smtpd???Exception` classes the remote client get's correct SMTP Server results. For logging purpose the default Exception.message is written to log. | ||
|
||
Please check RFC821 for correct response dialog sequences: | ||
|
||
|
@@ -248,7 +222,7 @@ You can access some important client and server values by using the `ctx` array | |
|
||
```ruby | ||
# helo string | ||
ctx[:helo] | ||
ctx[:server][:helo] | ||
|
||
# local (server's) infos | ||
ctx[:server][:local_ip] | ||
|
@@ -259,15 +233,21 @@ You can access some important client and server values by using the `ctx` array | |
ctx[:server][:remote_ip] | ||
ctx[:server][:remote_host] | ||
ctx[:server][:remote_port] | ||
|
||
# connection timestampe | ||
ctx[:server][:connected] | ||
|
||
# envelope mail from | ||
ctx[:envelope][:from] | ||
|
||
# envelope rcpt_to array | ||
ctx[:envelope][:to][0] | ||
|
||
# access messag in on on_message_data_event | ||
ctx[:message] | ||
# access message in on_message_data_event | ||
ctx[:message][:delivered] | ||
ctx[:message][:bytesite] | ||
ctx[:message][:data] | ||
|
||
``` | ||
|
||
|
||
|
@@ -286,6 +266,100 @@ We created a SMTP-Server e.g. to receive messages vie SMTP and store them to Rab | |
``` | ||
|
||
|
||
## New to version 2.x | ||
|
||
1. Modulelized | ||
2. Removed dependency to GServer | ||
3. Additional events to interact with | ||
4. Use logger to log several messages from severity :debug up to :fatal | ||
|
||
|
||
## From version 1.x to 2.x | ||
|
||
If you are already using MidiSmtpServer at a release 1.x it might be only some straight forward work to get your code work with version 2.x. | ||
|
||
#### Class | ||
|
||
##### 1.x | ||
|
||
```ruby | ||
MidiSmtpServer.new | ||
``` | ||
|
||
##### 2.x | ||
|
||
```ruby | ||
MidiSmtpServer::Smtpd.new | ||
``` | ||
|
||
#### Class initialize | ||
|
||
##### 1.x | ||
|
||
```ruby | ||
def initialize(port = 2525, host = "127.0.0.1", max_connections = 4, do_smtp_server_reverse_lookup = true, *args) | ||
``` | ||
|
||
##### 2.x | ||
|
||
```ruby | ||
def initialize(port = DEFAULT_SMTPD_PORT, host = DEFAULT_SMTPD_HOST, max_connections = 4, opts = {}) | ||
# opts may include | ||
opts = { do_dns_reverse_lookup: true } | ||
opts = { logger: myLoggerObject } | ||
``` | ||
|
||
#### On_event arguments order | ||
|
||
##### 1.x | ||
|
||
```ruby | ||
def on_helo_event(helo_data, ctx) | ||
def on_mail_from_event(mail_from_data, ctx) | ||
def on_rcpt_to_event(rcpt_to_data, ctx) | ||
``` | ||
|
||
##### 2.x | ||
|
||
```ruby | ||
def on_helo_event(ctx, helo_data) | ||
def on_mail_from_event(ctx, mail_from_data) | ||
def on_rcpt_to_event(ctx, rcpt_to_data) | ||
``` | ||
|
||
#### Exceptions | ||
|
||
##### 1.x | ||
|
||
```ruby | ||
MidiSmtpServerException | ||
MidiSmtpServer???Exception | ||
``` | ||
|
||
##### 2.x | ||
|
||
```ruby | ||
MidiSmtpServer::SmtpdException | ||
MidiSmtpServer::Smtpd???Exception | ||
``` | ||
|
||
#### Removed elements | ||
|
||
##### 1.x | ||
|
||
```ruby | ||
# class vars from gserver | ||
audit | ||
debug | ||
``` | ||
|
||
##### 2.x | ||
|
||
```ruby | ||
# not available anymore, is now controlled vy Logger | ||
``` | ||
|
||
|
||
## Package | ||
|
||
You can find, use and download the gem package from [RubyGems.org](http://rubygems.org/gems/midi-smtp-server) | ||
|
Oops, something went wrong.