agentic.email/smtp/entrypoint.sh
2026-10-05 21:34:12 +05:30

143 lines
3.9 KiB
Bash

#!/bin/sh
set -eu
: "${MAIL_HOSTNAME:=mail.gentic.email}"
: "${MAIL_DOMAIN:=gentic.email}"
: "${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"
postconf -e "smtp_header_checks = regexp:/etc/postfix/outbound_header_checks"
# 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