Wonderbolt is a config based email modifier, acting as local delivery agent and resubmitting emails via SMTP after modification.
Wonderbolt's main purpose is to enable simple email lists with external management of subscribers.
- Depends: python >= 3.4
- Recommends: python3-systemd
--config file
Required. This option takes one or more paths to config files. Later config files overwrite values from earlier ones.
--sasl-username username
Optional. See config option
require_sasl_username
.
All configuration options are optional. However, you probably want to change an option like envelope_rcpt_to
to avoid loops.
- bounce_from
string or
null
The From header that is used for bounce messages generated by Wonderbolt. If not specified or
null
, the header is set to Mail Delivery System <MAILER-DAEMON@hostname>, where hostname is replaced by the configuredhostname
.
- envelope_mail_from
string or
null
Bounce address for the new delivery of the email. If this setting is
null
, it will be derived from the From email header.
- envelope_rcpt_to
list of strings or
null
Recipients for new delivery of the email. If this setting is
null
, it will be derived from the To email header.
- header_add
mapping
Adds header values without removing/changing existing header lines. Performed after
header_replace
andheader_add_if_missing
. Therefore,header_add
adds a header a second time if key overlaps withheader_replace
and/orheader_add_if_missing
are present.
- header_add_if_missing
mapping
Adds header values only if header with the given key does not exist. Performed after
header_replace
, but beforeheader_add
. Therefore,header_add
adds a header a second time if key overlaps withheader_add_if_missing
are present.
- header_replace
mapping
Removes all existing headers with the given keys and adds the new values.
- hostname
string
The configured hostname is used in the content of bounce messages generated by Wonderbolt and is part of the default value for the
bounce_from
option.
- reject_msg_requirements
string
Error message used if emails are rejected by Wonderbolt due to violated
require_
configurations. This message is usually contained in a bounce message generated by the MTA and delivered to the sender afterwards.
- require_from
list of strings or
"envelope_rcpt_to"
orfalse
Enables to reject mails if the From email header does not fulfill a condition.
- list of strings: From must be contained in this list.
"envelope_rcpt_to"
: From must be contained in theenvelope_rcpt_to
list. If this option is set,envelope_rcpt_to
must be set and notnull
.false
: Disables checks (default).
- require_sasl_username
list of strings or
"envelope_rcpt_to"
orfalse
Enables to reject mails if the SASL username does not fulfill a condition. Same parameters as for
require_from
.For this feature to work,
--sasl-username
has to be specified on delivery.Note
While this feature is named after the SASL (Simple Authentication and Security Layer), there is no aspect of the implementation that limits the functionality to this exact authentication protocol.
- sasl_recipient_delimiter
string
Recipient delimiters only affect the interpretation of
envelope_rcpt_to
ifrequire_sasl_username
is set to this value. The local part of all recipients is stripped from all characters occurring after a first delimiter for comparing with the SASL username.This option should be set to the same value as the
recipient_delimiter
option of the postfix server. Every character in the string is treated as a delimiter. An empty string (default) corresponds to no delimiters.
- smtp_server
string
SMTP server via which the email is submitted. Default is "localhost:25".
Example of a wonderbolt config without a specific use case.
{
"reject_msg_requirements": "Rejected due to unprivileged SASL user",
"header_add": {
"X-Header-1": 1,
"X-Header-3": "Value 3"
},
"header_replace": {
"X-Header-1": "Value 1",
"X-Header-2": "Value 2"
},
"envelope_mail_from": "Bounce To <bounce_to@example.com>",
"envelope_rcpt_to": [
"User Name <user@example.org>",
"user2@example.org"
],
"require_from": false,
"require_sasl_username": "envelope_rcpt_to",
"smtp_server": "mail.example.com:25"
}
master.cfg
wonderbolt unix - n n - - pipe
flags=Ohu
user=wonderbolt:wonderbolt
argv=/usr/local/bin/wonderbolt.py --config /etc/wonderbolt/${nexthop}.json --sasl-username ${sasl_username}
main.cfg
wonderbolt_destination_recipient_limit = 1
/etc/wonderbolt/list@example.org.json
{
"envelope_mail_from": "list+bounce@example.org",
"envelope_rcpt_to": [
"listadmin@example.org",
"user1@example.com",
"user2_lists@example.com"
],
"header_add_if_missing": {
"List-Id": "<test.example.org>",
"List-Post": "<mailto:list@example.org>",
"Precedence": "bulk"
},
"header_replace": {
"List-Help": "<mailto:listadmin@example.org>",
"List-Owner": "<mailto:listadmin@example.org>",
"List-Subscribe": "<mailto:listadmin@example.org?body=subscribe%20list%20list@example.org>",
"List-Unsubscribe": "<mailto:listadmin@example.org?body=unsubscribe%20list%20list@example.org>"
},
"require_sasl_username": "envelope_rcpt_to",
"sasl_recipient_delimiter": "_"
}
Note
The choice of which headers are kept and which are replaced is made such that the list should conform with all currently applicable RFCs.
This configuration follows RFC 2919 by not removing the List-Id of a "parent" mailing list by not removing any List-Id. Since it is hard to tell what an unexpected source for such a header is, it does pass a given List-Id through to the list in any case, which violates a SHOULD NOT of this RFC.
It further follows RFC 2369 by replacing the List-Help, List-Owner, List-Subscribe and List-Unsubscribe headers. The List-Post header could also be replaced.
maps/aliases (postfix virtual_alias_maps
)
list+bounce@example.org listadmin@example.org
Note
This aliasing of the list-admin address is done to use it as an envelope sender, which does not conflict with any sender policies defined by via the SPF and similar mechanisms.
maps/transport (postfix transport_maps
)
list@example.org wonderbolt:list@example.org
pipe(8), Postfix delivery to external command
ooooooo
oO0.....00OOOoo
oO0...........0Oo
oO000000000000000000o
o00Ooo000000000000000000OoOOo 0....000000000000000000000o ...........0000000000000000o 0...............000..00000000o
oOoO0OO..................O..0Oo0oooooo O........0.....0OOooo..O0....O 0O
00OO0.......000....00o ooO.::.......o O............000.....00o O.:.......0 O...........000000......0......00oo o0.........000000000...........0o o0........0000000.......0OOoo OOOO0.......0O0000000......0o oooo O............0OO000000.......O o0....0O oO...........0OO000000.......00OO........0o oO.........0OO00.00..............00....0o o0.......OOO0..0............0oo......0 O........0OO.................o 0......o O0.......00.................0 O0...0
ooooooooo oo0.......................o ooo
oOOOOOOOOOOO000OOOoo 0::......................
OOOOOOOOO000000000000000...0.............Oo0....O
OOOOOOO000000...........................Oo oOOo
- oO oOOO00000.::..00OOoooO00...........0o
0OO00000::.000Oo 0.............0o 0OO0000.:.0000 o............0o OOO0000.:.0000o o..........0 OOO0000.:.00OOo O..........o OOO0000::.00ooo o..........0 oOO0000.:.00O o...........O OO0000.:.000o oO0.........O oO00000.:.OOO 0.......0o oO0000.:.ooOo oO00....0o oO000.:.o oO oOO0.:0 o o O.0 Oo
GitLab Thumbnail Copyright BlackGryph0n Licensed under CC BY-NC 3.0