diff --git a/conf/postfix/main.cf b/conf/postfix/main.cf index 01af1b619..bf26f89c6 100644 --- a/conf/postfix/main.cf +++ b/conf/postfix/main.cf @@ -211,3 +211,11 @@ smtp_sasl_security_options = noanonymous # where to find sasl_passwd smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd {% endif %} + +{% if backup_mx_domains != "" %} +# Backup MX (secondary MX) +relay_domains = $mydestination {{backup_mx_domains}} +relay_recipient_maps = hash:/etc/postfix/relay_recipients +maximal_queue_lifetime = 20d +{% endif %} + diff --git a/hooks/conf_regen/19-postfix b/hooks/conf_regen/19-postfix index d6ddcb5ee..2e829055a 100755 --- a/hooks/conf_regen/19-postfix +++ b/hooks/conf_regen/19-postfix @@ -45,6 +45,21 @@ do_pre_regen() { cat <<<"[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" >${postfix_dir}/sasl_passwd fi + + # Use this postfix server as a backup MX + export backup_mx_domains="$(yunohost settings get 'email.smtp.smtp_backup_mx_domains' | sed "s/,/ /g")" + export backup_mx_emails="$(yunohost settings get 'email.smtp.smtp_backup_mx_emails_whitelisted' | sed "s/,/ /g")" + rm -f ${postfix_dir}/relay_recipients + touch ${postfix_dir}/relay_recipients + if [ -n "${backup_mx_domains}" ] && [ -n "${backup_mx_emails}" ] + then + for mail in ${backup_mx_emails} + do + echo "$mail OK" >> ${postfix_dir}/relay_recipients + done + postmap ${postfix_dir}/relay_recipients + fi + export main_domain export domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')" ynh_render_template "main.cf" "${postfix_dir}/main.cf" @@ -78,6 +93,11 @@ do_post_regen() { postmap /etc/postfix/sasl_passwd fi + if [ -e /etc/postfix/relay_recipients ]; then + chmod 750 /etc/postfix/relay_recipients* + chown postfix:root /etc/postfix/relay_recipients* + fi + postmap -F hash:/etc/postfix/sni python3 -c 'from yunohost.app import regen_mail_app_user_config_for_dovecot_and_postfix as r; r(only="postfix")' diff --git a/locales/en.json b/locales/en.json index b10293434..aa725ac90 100644 --- a/locales/en.json +++ b/locales/en.json @@ -462,6 +462,10 @@ "global_settings_setting_smtp_relay_password": "SMTP relay password", "global_settings_setting_smtp_relay_port": "SMTP relay port", "global_settings_setting_smtp_relay_user": "SMTP relay user", + "global_settings_setting_smtp_backup_mx_domains": "Domains to act as secondary MX for", + "global_settings_setting_smtp_backup_mx_domains_help": "Allow this server to act as a backup *secondary* MX domain for the listed domain. This means that if the main MX for the domain is not reachable (for example because of an outage), mails will still be sent to this server, which will keep them during a maximum of 20 days and try to relay them to the real destination once it goes back up. Several domains can be provided, separated by commas.", + "global_settings_setting_smtp_backup_mx_emails_whitelisted": "SMTP backup MX emails whitelist", + "global_settings_setting_smtp_backup_mx_emails_whitelisted_help": "When acting as a secondary MX, the exhaustive list of allowed recipient's email addresses must be provided (otherwise mails will be refused and discarded). Several entries can be provided, separated by commas.", "global_settings_setting_ssh_compatibility": "SSH Compatibility", "global_settings_setting_ssh_compatibility_help": "Compatibility vs. security tradeoff for the SSH server. Affects the ciphers (and other security-related aspects). See https://infosec.mozilla.org/guidelines/openssh for more info.", "global_settings_setting_ssh_password_authentication": "Password authentication", diff --git a/share/config_global.toml b/share/config_global.toml index 40b71ab19..d836e50d5 100644 --- a/share/config_global.toml +++ b/share/config_global.toml @@ -107,7 +107,7 @@ name = "Email" [email.pop3.pop3_enabled] type = "boolean" default = false - + [email.smtp] name = "SMTP" [email.smtp.smtp_allow_ipv6] @@ -117,7 +117,7 @@ name = "Email" [email.smtp.smtp_relay_enabled] type = "boolean" default = false - + [email.smtp.smtp_relay_host] type = "string" default = "" @@ -134,7 +134,7 @@ name = "Email" default = "" optional = true visible="smtp_relay_enabled" - + [email.smtp.smtp_relay_password] type = "password" default = "" @@ -142,6 +142,17 @@ name = "Email" visible="smtp_relay_enabled" help = "" # This is empty string on purpose, otherwise the core automatically set the 'good_practice_admin_password' string here which is not relevant, because the admin is not actually "choosing" the password ... + [email.smtp.smtp_backup_mx_domains] + type = "string" + default = "" + optional = true + + [email.smtp.smtp_backup_mx_emails_whitelisted] + type = "string" + default = "" + optional = true + visible = "smtp_backup_mx_domains" + [misc] name = "Other" [misc.portal] diff --git a/src/settings.py b/src/settings.py index abe1a8f13..4f42183be 100644 --- a/src/settings.py +++ b/src/settings.py @@ -335,6 +335,8 @@ def reconfigure_ssh_and_fail2ban(setting_name, old_value, new_value): @post_change_hook("smtp_relay_port") @post_change_hook("smtp_relay_user") @post_change_hook("smtp_relay_password") +@post_change_hook("smtp_backup_mx_domains") +@post_change_hook("smtp_backup_mx_emails_whitelisted") @post_change_hook("postfix_compatibility") def reconfigure_postfix(setting_name, old_value, new_value): if old_value != new_value: