Code Monkey home page Code Monkey logo

rabbitmq-email's Introduction

SMTP Gateway Plugin for RabbitMQ

Maps SMTP to AMQP (to convert an incoming email to an AMQP message) and AMQP to SMTP (to send an email from an AMQP message).

This implementation aims to replace the rabbitmq-smtp. It is based on a more advanced [gen_smtp] (https://github.com/Vagabond/gen_smtp) rather than on [erlang-smtp] (https://github.com/tonyg/erlang-smtp).

This plugin is experimental. The described functionality is fully implemented and partially tested. I seek feature requests and early adopters.

If your installation of the plugin fails to process an e-mail, please:

  • re-send this e-mail to my instance of the plugin at 'rabbitmq[at]swimgate.eu'
  • create an issue and describe what you expected and what did happen

Please re-send the e-mail exactly the same way it failed for you. Do not use the forward button, do not add any explanation. I need the original MIME headers and body.

Mapping between SMTP and AMQP

The mapping works in both directions.

AMQP to SMTP Conversion

The adapter consumes a set of AMQP queues (e.g. email-out). Each queue is linked with a "default" domain name. When a message is consumed, its AMQP routing key is examined to determine the target SMTP address.

  • routing key that includes a domain part (i.e. the "@" character") is mapped directly to an SMTP address
  • routing key that includes the mailbox name only (i.e. without "@") is combined with the "default" domain name assigned to the queue

To send emails, you should bind these queues to your exchange and then publish a message to this exchange. For example:

import pika

connection = pika.BlockingConnection(
    pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='X', type='topic')
channel.queue_bind(exchange='X', queue='email-out', routing_key='#')

channel.basic_publish(exchange='X',
    routing_key='[email protected]',
    properties=pika.BasicProperties(
        content_type = 'text/plain',
        headers = {'Subject':'Greetings'}),
    body='Hello world!')
connection.close()

The message gets converted as shown in the table below. No content filtering is performed in this direction.

AMQP SMTP
                     | From: noreply@<domain>

routing_key | To message_id | Message-Id content_type | Content-Type headers | additional headers

SMTP to AMQP Conversion

The adapter listens for incoming emails. When an email arrives at the adapter, its SMTP "To" address is examined to determine how it should be routed through the system. First, the address is split into a mailbox name and a domain part.

  • the domain part (e.g. "@rabbitmq.com") is used to map to an AMQP virtual-host and AMQP exchange name
  • the mailbox name is mapped to an AMQP routing key

To receive the incoming emails, simply bind your queue(s) to this exchange. For example:

import smtplib
from email.mime.text import MIMEText

me = "[email protected]"
you = "[email protected]"

msg = MIMEText("Hello world!")
msg['From'] = me
msg['To'] = you
msg['Subject'] = 'Greetings'

s = smtplib.SMTP('localhost', 2525)
s.login("guest", "guest")
s.sendmail(me, [you], msg.as_string())
s.quit()

To catch emails sent to unknown recipients you may use an Alternate Exchange.

When server_auth is false the server accepts e-mails from any client. When server_auth is rabbitmq the clients need to provide a username and password that is checked against the rabbitmq server.

SMTP Body Extraction

The email_filter configuration option can be used to extract information from the email body. When enabled, the adapter will:

  • select only one part of multipart content depending on user priority;
  • remove extra space from text content.

The function is optional, to not extract anything and send the entire e-mail as <<"application/mime">> set:

{email_filter, false}

Otherwise the email_filter identifies a list of content-types that shall be preferred. For example:

  • Extract the text body or (when no text) the first binary attachement. This is the default behaviour.

    {email_filter, [
      {<<"text">>, <<"plain">>},
      {<<"text">>, undefined},
      {undefined, undefined}
    ]}

    Each 2-tuple represents content type/subtype. The atom undefined represents any content other than <<"multipart">>.

  • Extract the first binary attachement or (when no attachement) the text body.

    {email_filter, [
      {binary, undefined},
      {<<"text">>, <<"plain">>},
      {<<"text">>, undefined}
    ]}

    The atom binary represents any content other than <<"text">> and <<"multipart">>.

SMTP Headers Extraction

Depending on the email_headers option the message gets converted as shown in the table below. The adapter will pass to AMQP only selected MIME headers

{email_headers, ["subject", "from", "charset"]},
SMTP AMQP
From
To exchange, routing_key
                     | message_id
                     | timestamp

Subject | Subject Content-Type | content_type

Installation

RabbitMQ Configuration

Add the plug-in configuration section. See RabbitMQ Configuration for more details.

For example:

{rabbitmq_email, [
    % gen_smtp server parameters
    % see https://github.com/Vagabond/gen_smtp#server-example
    {server_config, [
        [{port, 2525}, {protocol, tcp}, {domain, "example.com"}, {address,{0,0,0,0}}]
    ]},
    % how clients are authenticated; either 'false' or 'rabbitmq' (default)
    {server_auth, rabbitmq},
    % whether STARTTLS shall be offered; either 'true' or 'false' (default)
    {server_starttls, true},
    % inbound email exchanges: [{email-domain, {vhost, exchange}}, ...}
    {email_domains,
        [{<<"example.com">>, {<<"/">>, <<"email-in">>}}
    ]},

    % outbound email queues: [{{vhost, queue}, email-domain}, ...]
    {email_queues,
        [{{<<"/">>, <<"email-out">>}, <<"example.com">>}
    ]},
    % sender indicated in the From header
    {email_from, <<"noreply">>},
    % sender indicated in the SMTP from
    {client_sender, "[email protected]"},
    % gen_smtp client parameters
    % see https://github.com/Vagabond/gen_smtp#client-example
    {client_config, [
        {relay, "smtp.example.com"}
    ]}
    ...
]}

Postfix Integration

You may want to run a standard Postfix SMTP server on the same machine and forward to the RabbitMQ plug-in only some e-mail domains.

  • Edit /etc/postfix/main.cf

    • Add the domains to be processed by RabbitMQ to the relay_domains list

      relay_domains = $mydestination, example.com
      
    • Make sure the transport_maps file is enabled

      transport_maps = hash:/etc/postfix/transport
      
  • Add links to the plug-in to the /etc/postfix/transport file

    example.com smtp:mail.example.com:2525
    .example.com smtp:mail.example.com:2525
    

Installation from source

Build Status

If you are on a Debian-based system then you need the erlang-nox, erlang-dev and erlang-src packages installed. If you are building and installing Erlang from source then you must ensure that openssl is installed on your system.

Build and activate the RabbitMQ plug-in rabbitmq-email. See the Plugin Development Guide for more details.

$ git clone https://github.com/gotthardp/rabbitmq-email.git
$ cd rabbitmq-email
$ make dist

To enable non-ASCII characters in e-mails use

$ EICONV=1 make dist

This is optional as it requires an Erlang NIF (eiconv). It is built automatically, but its module (eiconv-1.1.ez) is not portable to other platforms. When eiconv is disabled the rabbitmq-email plugin will ignore both header and content encoding schemes.

History

  • 0.1.0 (Dec 22, 2015)
    • Compatibility changes for RabbitMQ 3.6.x.
  • 0.0.2 (Nov 14, 2015)
    • Supports authentication using RabbitMQ database.
    • Payload filtering is now optional (Issue #7).
  • 0.0.1 (May 12, 2015) First release.

Copyright and Licensing

Copyright (c) 2014-2015 Petr Gotthard [email protected]

This package is subject to the Mozilla Public License Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://mozilla.org/MPL/2.0/.

Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License.

rabbitmq-email's People

Contributors

gotthardp avatar xtang avatar dumbbell avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.