Skip to content

Commit

Permalink
upd: rewrite README.md for new parts of release 2.x
Browse files Browse the repository at this point in the history
upd: change major release for beiing INCOMPATIBLE for version 1.x
up: rewrite example to bei compatible
  • Loading branch information
TomFreudenberg committed Mar 23, 2015
1 parent 1661daf commit 2484eda
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 94 deletions.
174 changes: 124 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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

Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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:

Expand Down Expand Up @@ -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]
Expand All @@ -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]

```


Expand All @@ -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)
Expand Down
Loading

0 comments on commit 2484eda

Please sign in to comment.