Skip to content
A simple, Sinatra inspired, SMTP routing server.
Python
Find file
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
examples
smtproutes
test
.gitignore
LICENSE.txt
README.markdown
setup.py

README.markdown

SMTPRoutes

SMTPRoutes is a light weight SMTP server built on top of Secure-SMTPD.

It's what you'd get if Sinatra and SMTP had a baby.

Installation

$ easy_install smtproutes

Note: You must use easy_install here. If you use pip there will be conflicting dependencies and things won't work.

Routes

Routes are specified via a regex provided in the route decorator.

from smtproutes import Route
from smtproutes.decorators import route

class ExampleRoute(Route):
    @route(r'myroute@.*')
    def my_route(self):
        print self.mailfrom.email

When invoked a route will have access to the following instance variables:

  • self.message the parsed email message.
  • self.mailfrom a contact object indicating who the message was received from.
  • self.tos an array of contact objects extracted from the To field.
  • self.ccs an array of contact objects extracted from the CC field.
  • self.bccs an array of contact objects extracted from the BCC field.

Any named groups specified in the route regex will be availble as instance variables.

class ExampleRoute(Route):

    @route(r'(?P<prefix>open)@(?P<suffix>.*)')
    def open_route(self):
        print "%s at %s sent the message: \n\n %s" % (
            self.prefix,
            self.suffix,
            self.message
        )

Sender Authentication

Email is vulnerable to spoofing attacks. SMTPRoutes allows you to provide an authentication object to protect against these.

An authentication class can be provided in the sender_auth kwarg of a route decorator.

@route(r'(?P<prefix>spf)@(?P<suffix>.*)', sender_auth=SPFAuth)
def spf_route(self):
    print "%s at %s sent the message: \n\n %s" % (
        self.prefix,
        self.suffix,
        self.message
    )

Currently the following sender authentication methods are supported:

You can provide multiple authentication approaches in the sender_auth kwarg, if any pass the route will be called:

@route(r'(?P<prefix>spf_google)@(?P<suffix>.*)', sender_auth=[SPFAuth, GmailSPFAuth])
def google_apps_spf_route(self):
    print "%s at %s sent the message: \n\n %s" % (
        self.prefix,
        self.suffix,
        self.message
    )

Running a Server

The server is a thin abstraction on top of secure-smtpd (https://github.com/bcoe/secure-smtpd).

  • SSL is supported.
  • Basic SMTP authentication is supported.

Create an instance of the server using any of the configuration options specified in the secure-smtpd project.

from smtproutes import Server

server = Server(('0.0.0.0', 25), None)

Once the server is created, you can register routes with it and start it running:

from example_route import ExampleRoute
server.add_route(ExampleRoute).start()

The server will now be listening on port 25 for inbound SMTP messages.

The Contact Objects

self.mailfrom, self.tos, self.ccs, and self.bccs each contain instances of contact objects:

  • contact.name the name extracted from the email address.
  • contact.email the email of the contact.

The Message Object

self.message is available as an instance variable when a route is executed.

self.messsage is a subclass of email.message.Message described here: http://docs.python.org/library/email.message.html#module-email.message

Extended functionality:

  • message.body the plain text body of the message.
  • message.attachments the attachments on the message.

Additional Support for Attachments

self.message has been extended upon to include an attachments property, which contains a list of pre-processed attachments:

  • attachment.filename the filename of the attachment.
  • attachment.data the binary data of the attachment.
  • attachment.extension the file extension of the attachment.
  • attachment.mime_type the mime type of the attachment.

License

ISC, see LICENSE.txt

Something went wrong with that request. Please try again.