smtp-pigeon

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 1, 2022 License: MIT

README

                   __                    _
   _________ ___  / /_____        ____  (_)___ ____  ____  ____
  / ___/ __ `__ \/ __/ __ \______/ __ \/ / __ `/ _ \/ __ \/ __ \
 (__  ) / / / / / /_/ /_/ /_____/ /_/ / / /_/ /  __/ /_/ / / / /
/____/_/ /_/ /_/\__/ .___/     / .___/_/\__, /\___/\____/_/ /_/
                  /_/         /_/      /____/

smtp-pigeon

smtp-pigeon is a tiny SMTP server that accepts mail and delivers it as a HTTP POST request. By default it uses a JSON formatted payload, but you can provide any template you want.

If you have tools generating mail reports such as Debians unattended upgrades but don't want to configure and run Postfix, SPF & DKIM & DMARC, etc or simply want to funnel those reports into a "please, anything but email" service; smtp-pigeon can act as the carrier.

  • Configurable payload (via Go's template engine)
  • Configurable headers
  • Portable Go binary
  • Tiny memory footprint

Usage

Run smtp-pigeon with the --url url option. By default smtp-pigeon will only accept connections from 127.0.0.1 at port 1025.

See --help for other options.

smtp-pigeon --url https://my.endpoint.com/mail
# => smtp-pigeon listening at 127.0.0.1:1025

By default smtp-pigeon POSTs the following JSON:

{
  "id": "per-message-uuid",
  "timestamp": "RFC 3399 datetime",
  "sender": "from@address",
  "recipients": ["to@address", "another@address"],
  "body": "multiline string",
  "subject": "string"
}

You can configure what smtp-pigeon POSTs with the --template flag, using any standard Go templating functions. You are not limited to sending JSON but the Content-Type header is set to application/json by default. You must override it with your own --header flag.

smtp-pigeon is intended to be run by systemd or any container runtime and does not have a daemon form. These systems should be used to handle any "service" requirements such as stop, start, restart and log aggregation.

Important caveats and gotchas:

  • Authentication

    smtp-pigeon provides no authentication methods and will allow any mail client to connect and send mail.

    Do not run smtp-pigeon on a world accessible port without recognizing the consequences.

  • Message Content

    smtp-pigeon performs no message screening. Whatever is sent in the mail will be passed along. This could include large amounts of encoded data if a service attaches a file for example. This may have repercussions downstream at the endpoint.

  • Delivery Guarantee

    smtp-pigeon does not currently cache messages for re-delivery, if the POST fails for any reason (due to a crash, network error, endpoint failure, etc), the message will not be re-attempted. Do not rely on smtp-pigeon for business critical messaging.

  • MTAs

    You will still need an MTA to deliver local mail to smtp-pigeon.

    An easy to use MTA is sSMPT which provides a sendmail interface and runs daemon-less. Simply set mailhub=localhost:1025.

Templating

You can specify a custom template using Go's text/template library.

Hint: You can use more complex templates by passing --template """$(cat template.txt)""" or similar, depending on your shell.

The following are available in the template:

  • .ID

    string

    UUID generated for each SMTP session, which effectively means for each message.

  • .Timestamp

    time.Time

    Marks the initial SMTP connection time, this may be different from the Date header. Will always be present. Will be in server timezone. You can convert to UTC via {{.Timestamp.UTC.Format "2006-01-02T15:04:05Z07:00" }}. See time Constants, note the string given indicates the format to use, not the time value. Date header may or may not be given by the mail client.

  • .Sender

    string

    Provided by the SMTP FROM command, this may be different to the From header. Will always be present, will always have one address. From header may or may not be given by the mail client.

  • .Recipients

    list of strings

    Each string will be provided by the SMTP RCPT command, this may be different to the To header. Will always be present, will always have at least one address. To header may or may not be given by the mail client.

  • .Data

    string

    Provided by the SMTP DATA command. This contains the raw message data sent to the server, including headers, etc.

  • .Body

    string

    mail.Message.Body, as parsed by net/mail. Converted to string from io.Reader for convenience.

  • .Header

    mail.Header

    See net/mail.Header. You can safely access header values in your template with {{.Header.Get "Subject"}}, which will return "" if the header does not exist.

Testing the Server

You can manually inspect smtp-pigeons behaviour by doing the following:

Run the server. Consider generating a ptsv2.com endpoint to use or running a netcat listen server.

smtp-pigeon \
  --url https://my.endpoint.com/mail \
  --header "Authorization: Bearer my_auth_token" \
  --header "MyService-Node: $(hostname)" \
  --host 0.0.0.0 \
  --port 9925
# => smtp-pigeon listening at 0.0.0.0:9925

Send mail via netcat.

echo """EHLO localhost
MAIL FROM:<[email protected]>
RCPT TO:<[email protected]>
RCPT TO:<[email protected]>
DATA
Subject: ON MY WAY
From: Gordon Freeman <[email protected]>
To: Eli Vance <[email protected]>
Cc: Issac Kleiner <[email protected]>

hey guys running l8 2day
on the tram now
cu soon
.""" | ncat localhost 9925

# => 220 localhost ESMTP Service Ready
# => 250-Hello localhost
# => 250-PIPELINING
# => 250-8BITMIME
# => 250-ENHANCEDSTATUSCODES
# => 250-CHUNKING
# => 250-AUTH PLAIN
# => 250 SIZE 1048576
# => 250 2.0.0 Roger, accepting mail from <[email protected]>
# => 250 2.0.0 I'll make sure <[email protected]> gets this
# => 250 2.0.0 I'll make sure <[email protected]> gets this
# => 354 2.0.0 Go ahead. End your data with <CR><LF>.<CR><LF>
# => 250 2.0.0 OK: queued

Server logs, note how a new session (and with it, a new message id) is automatically created after delivery. Session reset and logout messages will indicate whether a POST request was made or not.

c7f132cb-6043-4964-9853-02133a1e3181: New session
c7f132cb-6043-4964-9853-02133a1e3181: MAIL: [email protected]
c7f132cb-6043-4964-9853-02133a1e3181: RCPT: [email protected]
c7f132cb-6043-4964-9853-02133a1e3181: RCPT: [email protected]
c7f132cb-6043-4964-9853-02133a1e3181: DATA: [redacted (222 bytes)]
c7f132cb-6043-4964-9853-02133a1e3181: POST returned status: 200
c7f132cb-6043-4964-9853-02133a1e3181: Session reset after POST
02d6aebf-bfac-4c1f-9b7d-b9e781c7f1d1: New session
02d6aebf-bfac-4c1f-9b7d-b9e781c7f1d1: Session logout without POST

Received payload:

{
  "id": "c7f132cb-6043-4964-9853-02133a1e3181",
  "timestamp": "2022-01-01T10:10:20Z",
  "sender": "[email protected]",
  "recipients": ["[email protected]", "[email protected]"],
  "body": "hey guys running l8 2day\non the tram now\ncu soon\n",
  "subject":"ON MY WAY"
}

See also

Directories

Path Synopsis
cmd
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL