Mailing List
Running your own mail server is a challenge, and a mailing list even more so. There are some simple methods that can be employed using smptd(8) aliases.
OpenSMTPd
The
dev
alias delivers mail to three locations:
-
rset-dev-YYYY.mbox
for yearly archive -
local
marc
user used to build a HTML list archive - Comma separated list of users
smtpd: → ./rinstall hub/smtpd.conf /etc/mail/smtpd.conf → ./rinstall members /etc/mail/members && rcctl restart smtpd → ./rsub /etc/mail/aliases <<-CONF → dev: /var/www/archive/rset-dev-$(date +%Y).mbox,marc,$(paste -sd ',' /etc/mail/members) → CONF
The relay configuration needs to accomplish thee things:
- Add list headers
- Expand list alias to include all members
- Block non-members
# smtpd.conf smtp max-message-size 1M table aliases file:/etc/mail/aliases table members file:/etc/mail/members filter "add_list_headers" proc-exec "/usr/local/libexec/smtpd/add_list_headers.awk" listen on any port 25 action "local" maildir "%{user.directory}/mail" alias <aliases> action "outbound" relay helo scriptedconfiguration.org match from any for rcpt-to "admin@scriptedconfiguration.org" action "local" match !from mail-from <members> for domain "scriptedconfiguration.org" reject match from any for domain "scriptedconfiguration.org" action "local" match from local for local action "local" match from local for any action "outbound"
Add List Headers
list_headers: → mkdir -p /usr/local/libexec/smtpd → ./rinstall hub/add_list_headers.awk /usr/local/libexec/smtpd
add_list_headers.awk was inspired by
opensmtpd-filter-rewrite-from
with some techiniques borrowed from
d78.org.
#!/usr/bin/awk -f BEGIN { FS = "|" OFS = FS _ = FS in_body[""] = 0 } "config|ready" == $0 { print("register|filter|smtp-in|data-line") print("register|ready") fflush() next } "config" == $1 { next } "filter" == $1 { if (NF < 7) { print("invalid filter command: expected >6 fields!") > "/dev/stderr" exit 1 } sid = $6 token = $7 line = substr($0, length($1$2$3$4$5$6$7) + 8) } "filter|smtp-in|data-line" == $1_$4_$5 { if (line == "") { # end of headers in_body[sid] = 1 } if (!in_body[sid] && match(toupper(line), /^FROM:[\t ]*/)) { print("filter-dataline", sid, token, "List-Id: <dev.scriptedconfiguration.org>") print("filter-dataline", sid, token, "List-Post: <mailto:dev@scriptedconfiguration.org>") print("filter-dataline", sid, token, "List-Owner: <mailto:ericshane@eradman.com> (Eric Radman)") print("filter-dataline", sid, token, "List-Unsubscribe: <mailto:admin@scriptedconfiguration.org?subject=unsubscribe>") print("filter-dataline", sid, token, "List-Help: <mailto:admin@scriptedconfiguration.org?subject=question>") print("filter-dataline", sid, token, "Precedence: list") } if (line == ".") { # end of data delete in_body[sid] } print("filter-dataline", sid, token, line) fflush() next }