first commit
This commit is contained in:
commit
cce9a8c9ba
73 changed files with 8665 additions and 0 deletions
17
smtp/Dockerfile
Normal file
17
smtp/Dockerfile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
FROM alpine:3.21
|
||||
|
||||
RUN apk add --no-cache postfix openssl
|
||||
|
||||
COPY main.cf /etc/postfix/main.cf
|
||||
COPY master.cf /etc/postfix/master.cf
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod 0644 /etc/postfix/main.cf /etc/postfix/master.cf && \
|
||||
chmod 0755 /entrypoint.sh && \
|
||||
mkdir -p /var/spool/postfix/pid
|
||||
|
||||
EXPOSE 25
|
||||
|
||||
HEALTHCHECK --interval=10s --timeout=3s --retries=5 \
|
||||
CMD postfix status >/dev/null 2>&1 || exit 1
|
||||
|
||||
CMD ["/entrypoint.sh"]
|
||||
142
smtp/entrypoint.sh
Normal file
142
smtp/entrypoint.sh
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
: "${MAIL_HOSTNAME:=mail.getall.help}"
|
||||
: "${MAIL_DOMAIN:=getall.help}"
|
||||
: "${INBOUND_DOMAINS:=${MAIL_DOMAIN}}"
|
||||
: "${RELAY_DOMAINS_FILE:=/data/relay_domains/domains.list}"
|
||||
: "${RELAY_DOMAINS_REFRESH:=60}"
|
||||
: "${BACKEND_INGEST_HOST:=backend}"
|
||||
: "${BACKEND_INGEST_PORT:=2525}"
|
||||
|
||||
case "${MAIL_HOSTNAME}" in
|
||||
""|*[!A-Za-z0-9._-]*)
|
||||
echo "MAIL_HOSTNAME contains invalid characters" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${BACKEND_INGEST_HOST}" in
|
||||
""|*[!A-Za-z0-9._-]*)
|
||||
echo "BACKEND_INGEST_HOST must be an IPv4 address or DNS hostname" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${BACKEND_INGEST_PORT}" in
|
||||
""|*[!0-9]*)
|
||||
echo "BACKEND_INGEST_PORT must be numeric" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [ "${BACKEND_INGEST_PORT}" -lt 1 ] || [ "${BACKEND_INGEST_PORT}" -gt 65535 ]; then
|
||||
echo "BACKEND_INGEST_PORT must be between 1 and 65535" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
validate_domain() {
|
||||
domain="$1"
|
||||
printf '%s\n' "${domain}" | awk '
|
||||
/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/ {
|
||||
valid = 1
|
||||
}
|
||||
END { exit !valid }
|
||||
'
|
||||
}
|
||||
|
||||
install_relay_maps() {
|
||||
relay_domains_tmp="$(mktemp)"
|
||||
transport_tmp="$(mktemp)"
|
||||
seen_tmp="$(mktemp)"
|
||||
|
||||
add_domain() {
|
||||
raw_domain="$1"
|
||||
domain="$(printf '%s' "${raw_domain}" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')"
|
||||
if [ -z "${domain}" ]; then
|
||||
return 0
|
||||
fi
|
||||
if ! validate_domain "${domain}"; then
|
||||
echo "Skipping invalid relay domain: ${raw_domain}" >&2
|
||||
return 0
|
||||
fi
|
||||
if grep -Fxq "${domain}" "${seen_tmp}" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
printf '%s\n' "${domain}" >> "${seen_tmp}"
|
||||
printf '%s OK\n' "${domain}" >> "${relay_domains_tmp}"
|
||||
printf '%s smtp:[%s]:%s\n' \
|
||||
"${domain}" "${BACKEND_INGEST_HOST}" "${BACKEND_INGEST_PORT}" \
|
||||
>> "${transport_tmp}"
|
||||
}
|
||||
|
||||
old_ifs="${IFS}"
|
||||
IFS=','
|
||||
for raw_domain in ${INBOUND_DOMAINS}; do
|
||||
add_domain "${raw_domain}"
|
||||
done
|
||||
IFS="${old_ifs}"
|
||||
|
||||
if [ -f "${RELAY_DOMAINS_FILE}" ]; then
|
||||
while IFS= read -r line || [ -n "${line}" ]; do
|
||||
add_domain "${line}"
|
||||
done < "${RELAY_DOMAINS_FILE}"
|
||||
fi
|
||||
|
||||
if [ ! -s "${relay_domains_tmp}" ]; then
|
||||
rm -f "${relay_domains_tmp}" "${transport_tmp}" "${seen_tmp}"
|
||||
echo "At least one inbound relay domain is required" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
install -m 0644 "${relay_domains_tmp}" /etc/postfix/relay_domains
|
||||
install -m 0644 "${transport_tmp}" /etc/postfix/transport
|
||||
postmap /etc/postfix/relay_domains
|
||||
postmap /etc/postfix/transport
|
||||
rm -f "${relay_domains_tmp}" "${transport_tmp}" "${seen_tmp}"
|
||||
}
|
||||
|
||||
install_relay_maps
|
||||
|
||||
postconf -e "myhostname = ${MAIL_HOSTNAME}"
|
||||
postconf -e "mydomain = ${MAIL_DOMAIN}"
|
||||
postconf -e "myorigin = \$mydomain"
|
||||
|
||||
# STARTTLS cert for inbound providers (Gmail, Zoho, etc.)
|
||||
mkdir -p /etc/postfix/certs
|
||||
if [ ! -f /etc/postfix/certs/smtpd.crt ]; then
|
||||
openssl req -new -x509 -days 825 -nodes \
|
||||
-subj "/CN=${MAIL_HOSTNAME}" \
|
||||
-keyout /etc/postfix/certs/smtpd.key \
|
||||
-out /etc/postfix/certs/smtpd.crt
|
||||
chmod 600 /etc/postfix/certs/smtpd.key
|
||||
chmod 644 /etc/postfix/certs/smtpd.crt
|
||||
fi
|
||||
|
||||
# Postfix chroot cannot see Docker's resolver unless we copy these in.
|
||||
mkdir -p /var/spool/postfix/etc
|
||||
mkdir -p /var/spool/postfix/etc/postfix/certs
|
||||
cp /etc/postfix/certs/smtpd.crt /var/spool/postfix/etc/postfix/certs/smtpd.crt
|
||||
cp /etc/postfix/certs/smtpd.key /var/spool/postfix/etc/postfix/certs/smtpd.key
|
||||
chmod 644 /var/spool/postfix/etc/postfix/certs/smtpd.crt
|
||||
chmod 600 /var/spool/postfix/etc/postfix/certs/smtpd.key
|
||||
|
||||
for file in resolv.conf hosts nsswitch.conf; do
|
||||
if [ -f "/etc/${file}" ]; then
|
||||
cp "/etc/${file}" "/var/spool/postfix/etc/${file}"
|
||||
fi
|
||||
done
|
||||
|
||||
postfix check
|
||||
|
||||
if [ "${RELAY_DOMAINS_REFRESH}" -gt 0 ] 2>/dev/null; then
|
||||
(
|
||||
while true; do
|
||||
sleep "${RELAY_DOMAINS_REFRESH}"
|
||||
if install_relay_maps; then
|
||||
postfix reload >/dev/null 2>&1 || true
|
||||
fi
|
||||
done
|
||||
) &
|
||||
fi
|
||||
|
||||
exec postfix start-fg
|
||||
43
smtp/main.cf
Normal file
43
smtp/main.cf
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Internet-facing inbound relay + trusted outbound for Agmail.
|
||||
compatibility_level = 3.6
|
||||
myhostname = mail.getall.help
|
||||
mydomain = getall.help
|
||||
myorigin = $mydomain
|
||||
inet_interfaces = all
|
||||
inet_protocols = ipv4
|
||||
|
||||
mydestination =
|
||||
local_recipient_maps =
|
||||
local_transport = error:local delivery disabled
|
||||
relay_domains = lmdb:/etc/postfix/relay_domains
|
||||
transport_maps = lmdb:/etc/postfix/transport
|
||||
|
||||
# Internet clients may only send to relay_domains (inbound).
|
||||
# Docker/backend clients in mynetworks may relay outbound to the public internet.
|
||||
mynetworks = 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
|
||||
smtpd_relay_restrictions = permit_mynetworks, reject_unauth_destination
|
||||
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination
|
||||
|
||||
# Match the backend's 25 MiB inbound limit.
|
||||
message_size_limit = 26214400
|
||||
mailbox_size_limit = 0
|
||||
|
||||
# Keep transient backend failures queued for retry.
|
||||
minimal_backoff_time = 60s
|
||||
maximal_backoff_time = 3600s
|
||||
maximal_queue_lifetime = 1d
|
||||
bounce_queue_lifetime = 1d
|
||||
|
||||
# Opportunistic TLS for internet senders and the backend hop.
|
||||
# Gmail/Zoho require a working STARTTLS offer; certs are generated in entrypoint.sh.
|
||||
smtpd_tls_cert_file = /etc/postfix/certs/smtpd.crt
|
||||
smtpd_tls_key_file = /etc/postfix/certs/smtpd.key
|
||||
smtpd_tls_security_level = may
|
||||
smtpd_tls_loglevel = 1
|
||||
smtp_tls_security_level = may
|
||||
|
||||
# Log directly to the container output.
|
||||
maillog_file = /dev/stdout
|
||||
|
||||
alias_maps =
|
||||
alias_database =
|
||||
25
smtp/master.cf
Normal file
25
smtp/master.cf
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
smtp inet n - n - - smtpd
|
||||
pickup unix n - n 60 1 pickup
|
||||
cleanup unix n - n - 0 cleanup
|
||||
qmgr unix n - n 300 1 qmgr
|
||||
tlsmgr unix - - n 1000? 1 tlsmgr
|
||||
rewrite unix - - n - - trivial-rewrite
|
||||
bounce unix - - n - 0 bounce
|
||||
defer unix - - n - 0 bounce
|
||||
trace unix - - n - 0 bounce
|
||||
verify unix - - n - 1 verify
|
||||
flush unix n - n 1000? 0 flush
|
||||
proxymap unix - - n - - proxymap
|
||||
proxywrite unix - - n - 1 proxymap
|
||||
smtp unix - - n - - smtp
|
||||
relay unix - - n - - smtp
|
||||
showq unix n - n - - showq
|
||||
error unix - - n - - error
|
||||
retry unix - - n - - error
|
||||
discard unix - - n - - discard
|
||||
local unix - n n - - local
|
||||
virtual unix - n n - - virtual
|
||||
lmtp unix - - n - - lmtp
|
||||
anvil unix - - n - 1 anvil
|
||||
scache unix - - n - 1 scache
|
||||
postlog unix-dgram - - n - 1 postlog
|
||||
Loading…
Add table
Add a link
Reference in a new issue