emailwiz/emailwiz

476 lines
12 KiB
Bash
Executable File

#!/bin/sh
# _ _ _
# ___ _ __ ___ __ _(_) |_ _(_)____
# / _ \ '_ ` _ \ / _` | | \ \ /\ / / |_ /
#| __/ | | | | | (_| | | |\ V V /| |/ /
# \___|_| |_| |_|\__,_|_|_| \_/\_/ |_/___|
#
#
# THE SETUP
#
# Login info:
# SMTPs server: mx.domain.tld (${subdom}.${domain})
# SMTPs Setting: port 465, SSL/TLS, PLAIN
# IMAPs server: mx.domain.tld (${subdom}.${domain})
# IMAPs Setting: port 993, SSL/TLS, PLAIN
# User: user name w/o '@domain.tld'
# Firewall setting, open following port:
# SMPT port 25
# SMTPs port 465
# IMAPs port 993
# Mail will be stored in non-retarded Maildirs because it's ${current_year}. This
# makes it easier for use with isync, which is what I care about so I can have
# an offline repo of mail.
# The mailbox names are: Inbox, Sent, Drafts, Archive, Spam, Trash
# Use the typical unix login system for mail users. Users will log into their
# email with their passnames on the server. No usage of a redundant mySQL
# database to do this.
# Rspamd whitelists and blacklists are in /etc/rspamd/.local.d. Modify them to
# your own need.
#
# DEPENDENCIES BEFORE RUNNING
#
# 1. Modify "Paramater" section to your need.
# 2. Have a OpenBSD 6.7 system with a static IP and all that. Pretty much any
# default VPS offered by a company will have all the basic stuff you need.
# 3. Have a Let's Encrypt SSL certificate for mx.domain.tld
# (${subdom}.${domain}) using httpd(1) and acme-client(1).
# 4. If you've been toying around with your server settings trying to get
# smtpd/dovecot/rspamd/etc. I recommend you to clear out /etc/mail, /etc/dovecot
# , and /etc/rspamd/local.d yourself if needbe, because this script is build on
# top of only the defaults.
#
# Parameters
#
# Modify this section to your need
readonly domain='domain.tld'
readonly subdom='mx'
# DO NOT modify this part
readonly maildomain="${subdom}.${domain}"
readonly progname="$(basename "$0")"
# Certificate for smtp
readonly certfile="/etc/ssl/${maildomain}.fullchain.pem"
readonly keyfile="/etc/ssl/private/${maildomain}.key"
# RSA key for dkim
readonly dkimkey="/etc/mail/dkim/${domain}.key"
#
# Check privilege
#
if test "$(id -u)" != '0'; then
printf '%s: Root access required.\n' "${progname}"
printf '%s: Exiting...\n' "${progname}"
exit 1
fi
#
# Check dependency
#
printf '%s: Installing programs...\n' "${progname}"
pkg_add opensmtpd-filter-dkimsign dovecot dovecot-pigeonhole rspamd opensmtpd-filter-rspamd
if test ! -f /etc/doas.conf; then
printf '%s: doas(1) not configured.\n' "${progname}"
printf '%s: Exiting...\n' "${progname}"
exit 1
fi
#
# Check certificate
#
printf '%s: Checking Certificate files...' "${progname}"
if test -f "${certfile}" && test -f "${keyfile}"; then
printf ' Done\n'
else
printf ' File not found\n'
printf '%s: Note! You must first have a HTTPS/SSL Certificate for %s.
Use acme-client(1) and httpd(1) to get that and then rerun this script.' "${progname}" "${maildomain}"
printf '%s: Exiting...\n' "${progname}"
exit 1
fi
#
# Configure alternative server name ( /etc/mail/mailname )
#
printf '%s: Configuring alternative server name (/etc/mail/mailname)...\n' "${progname}"
test -f /etc/mail/mailname && cp -f /etc/mail/mailname /etc/mail/mailname.def
printf '%s\n' "${maildomain}" > /etc/mail/mailname
#
# Configure OpenSMTPD ( /etc/mail/smtpd.conf )
#
printf '%s: Configuring OpenSMTPD (smtpd.conf)...\n' "${progname}"
cp -f /etc/mail/smtpd.conf /etc/mail/smtpd.conf.def
cat << EOF > /etc/mail/smtpd.conf
# Generated by emailwiz
# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.
pki "${maildomain}" cert "${certfile}"
pki "${maildomain}" key "${keyfile}"
filter "check_rdns" phase connect match !rdns disconnect "550 no rDNS"
filter "check_fcrdns" phase connect match !fcrdns disconnect "550 no FCrDNS"
filter "rspamd" proc-exec "filter-rspamd"
filter "spam_triad" chain { "check_rdns", "check_fcrdns", "rspamd" }
filter "dkimsign" proc-exec "filter-dkimsign -d ${domain} -s ${subdom} -k ${dkimkey}" user _dkimsign group _dkimsign
table aliases file:/etc/mail/aliases
listen on lo0
listen on egress port 25 tls pki "${maildomain}" filter "spam_triad"
listen on egress port 465 smtps pki "${maildomain}" auth filter "dkimsign"
action "local_mail" lmtp "/var/dovecot/lmtp" alias <aliases>
action "outbound" relay helo "${maildomain}"
match from local for local action "local_mail"
match from local for any action "outbound"
match from any for domain "${domain}" action "local_mail"
match from any auth for any action "outbound"
EOF
#
# Configure Dovecot ( /etc/dovecot/dovecot.conf )
#
# By default, dovecot has a bunch of configs in /etc/dovecot/conf.d/ These
# files have nice documentation if you want to read it, but it's a huge pain to
# go through them to organize. Instead, we simply rewrite dovecot.conf because
# it's easier to manage.
printf '%s: Configuring Dovecot (dovecot.conf)...\n' "${progname}"
cp -f /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.def
cat << EOF > /etc/dovecot/dovecot.conf
# Generate by emailwiz
# Note that in the dovecot.conf, you can use:
# %u for username
# %n for the name in name@domain.tld
# %d for the domain
# %h the user's home directory
# Use imap and lmtp ( deliver mail for OpenSMTPD )
protocols = imap lmtp
# Our mail for each user will be in ~/Maildir, and the inbox will be ~/Maildir/Inbox
# The LAYOUT option is also important because otherwise, the boxes will be ".Sent" instead of "Sent".
mail_location = maildir:~/Maildir:INBOX=~/Maildir/Inbox:LAYOUT=fs
namespace inbox {
inbox = yes
mailbox Drafts {
special_use = \\Drafts
auto = subscribe
}
mailbox Spam {
special_use = \\Junk
auto = subscribe
autoexpunge = 30d
}
mailbox Sent {
special_use = \\Sent
auto = subscribe
}
mailbox Trash {
special_use = \\Trash
auto = subscribe
}
mailbox Archive {
special_use = \\Archive
auto = subscribe
}
}
# Use BSDAuth to authenticate the user
passdb {
driver = bsdauth
}
# Retrieves post-login information in /etc/passwd
userdb {
driver = passwd
}
# Outlook Express and Windows Mail works only with LOGIN mechanism, not the standard PLAIN:
auth_mechanisms = plain login
# Use plain user name instead of user@domain for login
auth_username_format = %n
# Configure SSL/TLS
# NOTE: If you have only plaintext mechanisms enabled
# (e.g. auth { mechanisms = plain login } ), ssl=yes and ssl=required are
# completely equivalent because in either case the authentication will fail
# unless SSL/TLS is enabled first
ssl = required
ssl_cert = <${certfile}
ssl_key = <${keyfile}
# Disable insecure IMAP
service imap-login {
inet_listener imap {
#port = 143
port = 0
}
inet_listener imaps {
#port = 993
#ssl = yes
}
}
# Configure LMTP
service lmtp {
unix_listener lmtp {
mode = 0666
}
}
# Configure sieve
protocol lmtp {
mail_plugins = \$mail_plugins sieve
}
plugin {
# The location of the user's main script storage. The active script
# in this storage is used as the main user script executed during
# delivery. The include extension fetches the :personal scripts
# from this location. When ManageSieve is used, this is also where
# scripts are uploaded. This example uses the file system as
# storage, with all the user's scripts located in the directory
# "~/sieve" and the active script (symbolic link) located at
# "~/.dovecot.sieve".
sieve = file:~/sieve;active=~/.dovecot.sieve
# If the user has no personal active script (i.e. if the location
# indicated in sieve= does not exist or has no active script), use
# this one:
sieve_default = /usr/local/lib/dovecot/sieve/default.sieve
# The include extension fetches the :global scripts from this
# location.
sieve_global = /usr/local/lib/dovecot/sieve/global/
}
EOF
#
# Generate sieve scripts for Dovecot ( /usr/local/lib/dovecot/sieve/* )
#
printf '%s: Generating sieve scripts for Dovecot ( /usr/local/lib/dovecot/sieve/* )...\n' "${progname}"
mkdir -p /usr/local/lib/dovecot/sieve/
# Default sieve script: put Rspamd-tagged mails into mailbox "Spam"
cat << EOF > /usr/local/lib/dovecot/sieve/default.sieve
require "fileinto";
if header :contains "X-Spam" "YES" {
fileinto "Spam";
}
EOF
# Compile sieve scripts
sievec /usr/local/lib/dovecot/sieve/default.sieve
#
# Configure user authentication for Dovecot ( /etc/login.conf )
#
printf '%s: Configuring user authentication for Dovecot (/etc/login.conf)...\n' "${progname}"
if ! grep -q 'dovecot' /etc/login.conf; then
cp -f /etc/login.conf /etc/login.conf.def
cat << EOF >> /etc/login.conf
#
# Dovecot entry
#
dovecot:\\
:openfiles-cur=1024:\\
:openfiles-max=2048:\\
:tc=daemon:
EOF
fi
# reload login.conf
cap_mkdb /etc/login.conf
#
# Configure rspamd ( /etc/rspamd/local.d/action.conf )
#
printf '%s: Configuring Rspamd (action.conf)...\n' "${progname}"
mkdir -p /etc/rspamd/local.d/
cat << EOF > /etc/rspamd/local.d/action.conf
# Generate by emailwiz
actions {
#reject = 15; # Reject when reaching this score
reject = null; # Disable Rejection
add_header = 6; # Add header when reaching this score
greylist = 4; # Apply greylisting when reaching this score (will emit "soft reject action")
}
EOF
printf '%s: Configuring Rspamd black/whitelist (multimap.conf)...\n' "${progname}"
for x in 'local_bl_from.map.inc' 'local_bl_ip.map.inc' 'local_bl_rcpt.map.inc' \
'local_wl_from.map.inc' 'local_wl_ip.map.inc' 'local_wl_rcpt.map.inc'; do
touch "/etc/rspamd/local.d/${x}"
chmod 666 "/etc/rspamd/local.d/${x}"
done
cat << EOF > /etc/rspamd/local.d/multimap.conf
# Blacklists
local_bl_ip {
type = "ip";
map = "\$LOCAL_CONFDIR/local.d/local_bl_ip.map.inc";
symbol = "LOCAL_BL_IP";
description = "Local ip blacklist";
score = 5;
}
local_bl_from {
type = "from";
map = "\$LOCAL_CONFDIR/local.d/local_bl_from.map.inc";
symbol = "LOCAL_BL_FROM";
description = "Local from blacklist";
score = 5;
}
local_bl_rcpt {
type = "rcpt";
map = "\$LOCAL_CONFDIR/local.d/local_bl_rcpt.map.inc";
symbol = "LOCAL_BL_RCPT";
description = "Local rcpt blacklist";
score = 5;
}
# Whitelists
local_wl_ip {
type = "ip";
map = "\$LOCAL_CONFDIR/local.d/local_wl_ip.map.inc";
symbol = "LOCAL_WL_IP";
description = "Local ip whitelist";
score = -5;
}
local_wl_from {
type = "from";
map = "\$LOCAL_CONFDIR/local.d/local_wl_from.map.inc";
symbol = "LOCAL_WL_FROM";
description = "Local from whitelist";
score = -5;
}
local_wl_rcpt {
type = "rcpt";
map = "\$LOCAL_CONFDIR/local.d/local_wl_rcpt.map.inc";
symbol = "LOCAL_WL_RCPT";
description = "Local rcpt whitelist";
score = -5;
}
EOF
#
# Configure opensmtpd-filter-dkimsign
#
printf '%s: Generating dkim keys...\n' "${progname}"
mkdir -p /etc/mail/dkim
doas -u _dkimsign openssl genrsa -out "${dkimkey}" 2048
#
# Restart daemons
#
for x in 'smtpd' 'dovecot' 'rspamd'; do
printf '%s: Enabling %s...' "${progname}" "${x}"
rcctl enable "${x}" 2>&1 > /dev/null && printf ' Done\n' || printf ' Failed\n'
printf '%s: Restarting %s...' "${progname}" "${x}"
rcctl restart "${x}" 2>&1 > /dev/null && printf ' Done\n' || printf ' Failed\n'
done
#
# Display DNS Record & Finish up
#
readonly pval="$(openssl rsa -in "${dkimkey}" -pubout \
| sed '1s/.*/p=/;:nl;${s/-----.*//;q;};N;s/\n//g;b nl;')"
readonly dkim_entry="${subdom}._domainkey.${domain} TXT v=DKIM1; k=rsa; ${pval}"
readonly dmarc_entry="_dmarc.${domain} TXT v=DMARC1; p=none; rua=mailto:postmaster@${domain}; fo=1"
readonly spf_entry="@ TXT v=spf1 mx a:${maildomain} -all"
cat << EOF > "${HOME}/dns_emailwiz"
${dkim_entry}
${dmarc_entry}
${spf_entry}
EOF
cat << EOF
_ _
| \ | | _____ ___
| \| |/ _ \ \ /\ / (_)
| |\ | (_) \ V V / _
|_| \_|\___/ \_/\_/ (_)
1. Add these three records to your DNS TXT records on either your registrar's site
or your DNS server:
${dkim_entry}
${dmarc_entry}
${spf_entry}
NOTE: You may need to omit the ".${domain}" portion at the beginning if
inputting them in a registrar's web interface.
Also saving these to ~/dns_emailwiz in case you want them in a file.
EOF