exim4 | SPF | DKIM ! DMARC | Firewall | dovecot | tomcat | Jwma | Blocklists
updated November 2025

the perfect email server on Debian Trixie

This write up is presented in the hope that more people will run there own email server rather than sign up to one of the big providers. In my opinion there is no excuse to not do this if you host a web site; there is a lot of fiddling, some obstacles to overcome, but it's not that difficult. For as much simplicity as possible I'm going to just stick with explaining what I do now for myself. There are lots of alternatives that I used to cover which I no longer will eg james instead of exim4, access to email other than by webmail, implementing mta-sts, checking email with spamassassin and online DNSBL such as Spamhaus etc. Much of the Bookworm based information is still vaild and you can find it here, some of it, particularly the tinkeing with exim4 config, is no longer correct though.

So first off despite what anyone else may tell you, upgrading to Trixie from Bookworm just works bar a few minor issues. There really is no sense in starting from scratch or moving to another server, as I have seen suggested elsewhere. Unfortunately most of the "minor" issues are around exim4. Please pay careful attention to details that look minor if you followed my earlier write ups; tweaks that worked nicely on Bookworm now put a spanner in the works.

exim4

All exim4 configuration, at least that part of it you may tamper with are held in the /etc/exim4 directory. If you're installing exim4 from scratch that process is largely unchanged; the exim-daemon-heavy package is unnecessary and I will give my current thoughts on spam later. Strangely, to get the option of an internet mail exchanger you have to edit the update-exim4.conf.conf file manually. Change dc_eximconfig_configtype='local' to dc_eximconfig_configtype='internet' and then never alter this file manually again.

The dpkg-reconfigure exim4-config routine runs as a part of the Debian install, but you can run it manually as root at any time if settings need to change. There's a handful of questions to be answered, some by selecting possible answers from a list and some by supplying relevant responses yourself.

Please select the mail server configuration type that best meets your needs
Select Internet site and confirm using the Tab key

Supply the system mail name				
This can be your own email domain or the output of the hostname -f command

IP-addresses to listen on			
Leave blank to allow Exim4 to listen for connections on all available network interfaces

Other destinations for which mail is accepted   
Supply a semi-colon separated list of domains not included in the system mail name answer

Domains to relay mail for
Machines to relay mail for
Leave answer blank for both of these

Keep number of DNS-queries minimal
Select No

Delivery method for local mail
I use the mbox format; all programs, including exim4, dovecot and email/webmail clients must be 
configured to use the same format

Split configuration into small files?		
I select No to use the single exim4.conf.template as opposed to the split config in the conf.d directory

This routine updates the update-exim4.conf.conf file, runs the update-exim4.conf procedure and restarts exim4 as this is necessary for config changes to be picked up. If you always manually run the update-exim4.conf procedure and restart exim4 after making configuration changes you don't need to remember when that is not necessary. Most configuration work will be done on the exim4.conf.template file, there are a few changes to make and some additions, which must be added in the correct place. So from top down:-

# List of sender networks (IP addresses) to _unconditionally_ relay
# _for_. If you intend to be SMTP AUTH server, you do not need to enter
# anything here.
hostlist relay_from_hosts = MAIN_RELAY_NETS

#CHANGED--added for dkim checking
acl_smtp_dkim = acl_check_dkim
### main/02_exim4-config_options
#################################


# Defines the access control list that is run when an
# SMTP MAIL command is received.
#

#CHANGED--added--ipv6 disallowed-----------------------
# copied from yea olde bullseye, seems to work in trixie
disable_ipv6=true
#check with netstat -tulpn | grep :25
#------------------------------------------------------
It's probably essential to not offer an ipv6 connection if you have been allocated a single ipv6 address rather than a /64. Having said that, not configuring an AAAA record for the mail exchanger makes this tweak unnecessary. Online blocklist do not descend below the granularity of a /64 and if you're not in full control there will surely be someone else in that range that will cause your email to be blocked or land in junk boxes. If you want to have ipv6 email, you effectively need to have control of a /64 range.
### main/03_exim4-config_tlsoptions
#################################

# TLS/SSL configuration for exim as an SMTP server.
# See /usr/share/doc/exim4-base/README.Debian.gz for explanations.

#!CHANGED*****added this *************************
MAIN_TLS_ENABLE = yes
#daemon_smtp_ports=smtp : 465 : 587 
#generate certificate & key:-
#/usr/share/doc/exim4-base/examples/exim-gencert

# but we only want webmail access so:-
daemon_smtp_ports = 25
#***************************************************
We allow the option for connecting servers to switch to an encrypted connection. If you wish to implement mta-sts, which as someone else pointed out is an absurdity (mail exchanger referring to a file delivered over https!), the self generated certificate will not do. IMO there's already enough things you must do to have hope of interoperability with the large providers, so I no longer attempt to force use of encryption from connecting servers. A script is provided to generate the standard certificate; when you run it most of the fields can be left blank, just set the required field to the name of your domain. Here's the command to create the cerytificate and key and how to add them into the configuration:-
root@mydomain.com:/usr/share/doc/exim4-base/examples# ./exim-gencert

# same file, set MAIN_TLS_CERTKEY to that file to enable. This takes
# precedence over all other settings regarding certificate and key file.

#!CHANGED*****added this *************************
MAIN_TLS_CERTIFICATE = /etc/exim4/exim.crt
MAIN_TLS_PRIVATEKEY = /etc/exim4/exim.key
#*************************************************

.ifdef MAIN_TLS_CERTKEY
tls_certificate = MAIN_TLS_CERTKEY
#####################################################
### end acl/00_exim4-config_header
#####################################################
##CHANGED---added--#############################-----------------------------------
### acl/10_exim4-check_dkim
#####################################################

acl_check_dkim:

  # Add a header with DKIM result
  warn
    add_header = X-DKIM-Result: $dkim_verify_status${if def:dkim_domain{ (domain=$dkim_domain)}}

  # Log failures
  warn
    condition = ${if eq{$dkim_verify_status}{fail}{yes}{no}}
    log_message = "DKIM verification failed for $sender_address"
    add_header = Subject: possible SPAM $h_Subject:
  # Default accept
  accept
#####################################################
### end acl/10_exim4-check_dkim
#####################################################
#------------------------------------------------------------------------------------------------
The idea here is that incoming email with incorrect dkim information is likely to be spam. It will not be rejected by this code, but the Subject: header will be marked as spam and it can be dropped into a junk box - more on that below.
### end router/300_exim4-config_real_local
#####################################################
#####################################################
### router/350_exim4-config_vdom_aliases
#*!CHANGED******this block of router code added
#####################################################

vdom_aliases:
  driver = redirect
  allow_defer
  allow_fail
  domains = dsearch;/etc/exim4/virtualhosts
  data = ${lookup{$local_part}lsearch{/etc/exim4/virtualhosts/$domain_data}}
  retry_use_local_part
  pipe_transport = address_pipe
  file_transport = address_file
  no_more

#####################################################
### end router/350_exim4-config_vdom_aliases
#####################################################
That 6th change/addition is the last needed in this main config file, although further work is necessary for that router code to control local delivery. This code allows for more flexibility in delivery than relying on the /etc/aliases file. So after saving the exim4.conf.template file, create the virtualhosts directory with a file in it for each of your local domains. This may look something like:-
root@mydomain.com:/etc/exim4# ls virtualhosts/
mydomain.org.uk  mydomain.com
and as an example of the files:-
root@mydomain.com:/etc/exim4# cat virtualhosts/mydomain.org.uk 
metja: nkadimeng@outlook.com
postmaster: david@localhost
david: david@localhost
*:	:blackhole:
So our server is responsible for email at mydomain.co.uk and mydomain.org; there are two real users at mydomain.org.uk in addition to postmaster, for whom every domain *should* have an email contact. Mail to david and postmaster will be delivered locally and metja's mail will be sent on to outlook.com. Anything not addressed to one of those 3 users will be blackholed.

In the 5th change to exim4.conf.template we altered the Subject: header to mark an email as potentially spammy. We can take advantage of that with an exim filter that will see doubtful mail not cluttering our INBOX. User david can create if necessary, a couple of email folders, spam and admin. To finally put those into use:-

root@mydomain.com:/etc/exim4# cat /home/david/.forward 
# Exim filter <<< important first line, distinguishes from ye olde .forward
if $header_subject: contains "SPAM" 
	then
	save "/home/david/mail/spam"
endif
if $header_subject: contains "Cron" 
	then
	save "/home/david/mail/admin"
endif
if $header_subject: contains "DenyHosts" 
	then
	save "/home/david/mail/admin"
endif
if $header_subject: contains "Report Domain:"
        then
        save "/home/david/mail/admin"
endif
and this is an appropriate place to briefly mention spam which I am hardly ever trobled with. In the past I've linked up exim4 with spamassassin, but that's a serious memory hog on a small server. I've also used an account at spamhaus, but it so seldom found anything in it's blocklists and I prefer to keep everything in house. In addition to dkim I do check incoming mail for SPF and drop anything that doesn't comply. I suggest see how it goes and check out other anti-spam possibilities, including my older how to if it proves to be necessary. Mentioning SPF leads us to the 2nd most important exim conf file on Debian based systems ie exim4.conf.localmacros, which you should create root:root owned.
root@mydomain.com: /etc/exim4# cat exim4.conf.localmacros 
MAIN_HARDCODE_PRIMARY_HOSTNAME = mydomain.com
MAIN_LOCAL_DOMAINS = @:localhost:dsearch;/etc/exim4/virtualhosts
CHECK_RCPT_VERIFY_SENDER = yes
CHECK_DATA_VERIFY_HEADER_SENDER = yes
CHECK_RCPT_SPF = true
DKIM_CANON = relaxed
DKIM_SELECTOR = 202002
DKIM_DOMAIN = ${domain:$h_from:}
DKIM_PRIVATE_KEY = /etc/exim4/rsa.private
The first line is a belt and braces; it should refer to an email domain on the server and should have been set by dpkg-reconfigure exim4-config, but we want to make sure exim doesn't pick up something inappropriate from /etc/hosts or /etc/mailname. The 2nd line points exim at our virtualhosts directory. Lines 3 to 5 implement some checking of incoming mail. But rather than the checks on incoming mail, the DKIM lines are all connected with signing our outgoing mail.

DKIM is one of the three authentication protocols we absolutely must correctly implement to have our outgoing mail accepted and delivered to INBOX rathjer than spam. Unlike the other two, DKIM is not purely a matter for DNS, rather there is a DNS and an exim component. The last two lines are on the exim side of things. The DKIM_DOMAIN line ensures that a single key can be used by all the domains that our server is configured to send mail for. The keys are generated as follows:-

root@mydomain.com:/etc/exim4# openssl genrsa -out rsa.private 1024
root@mydomain.com:/etc/exim4# openssl rsa -in rsa.private -out rsa.public -pubout -outform PEM

root@mydomain.com:/etc/exim4 chown Debian-exim:root rsa.*

root@mydomain.com:/etc/exim4# ls -l rsa*
-rw------- 1 Debian-exim root 916 Aug 29 16:18 rsa.private
-rw-r--r-- 1 Debian-exim root 272 Aug 29 16:18 rsa.public
Before discussing DNS set up of those three protocols we can quickly finish up the exim part of this journey. I create two files, sender_local_deny_exceptions and local_sender_blacklist. I believe the 2nd of those can contain a list of addresses or whole domains you do not wish to hear from, but I haven't used it yet. The first is a failsafe to ensure we do not get ourselves blocked:-
root@mydomain.com:/etc/exim4#cat sender_local_deny_exceptions
metja@mydomain.org.uk
david@mydomain.org.uk
postmaster@mydomain.org.uk
david@mydomain.com
postmaster@mydomain.com
Last of all a mention that in the exim4 config directory you will see a directory conf.d and a file passwd.client that I make no use of.

DNS

I've a seperate writeup that tells how to host your own DNS. Whether you choose to do this yourself or hand it to your ISP, here is what your mail server will need. Firstly an MX record for your domain, maybe you decide to create mx.mydomain.com; that subdomain (which is what a mail exchanger is as far as DNS is concerned) will need an A record and possible also an AAAA record (but see thr ipv6 conundrum above).

Then we need to implement the three protocols without which we cannot have confidence that our outgoing email will reach an INBOX. They allow recipient admins to check text records in our DNS and ensure email from our domain comply with commitments we make about them. However these records get created, I'll show how they should appear to the dig +short command.

SPF
Since all mail should originate from the mydomain.com server we can recommend that mail from ip address other than ours should be rejected. If you're not running an ipv6 ready mail exchanger, simply don't specify an ipv6 address.

root@mydomain.com: # dig +short TXT mydomain.com
"v=spf1 ip4:x.x.x.x ip6:xxxx:xxxx::xxxx -all"


DKIM
This technology allows recipient servers to check that email has not been altered in transit. The local mail exchanger encrypts the email with the private key - which is created as described above in the exim4 section- the corresponding public key is entered into the domain's DNS record from where it can be accessed by the receiving mail exchanger. The first and last lines (starting -----BEGIN and -----END) and the carriage returns are removed from the public key; a command line method to do this will be shown below.

This truncated version of our rsa.public file will be part of a *._domainkey subdomain of the form <selector>._domainkey.mydomain.com. The selector can be anything, a date reference is suggested.

root@mydomain.com:/etc/exim4# awk 'NR>1{a[++k]=$0}END{for(i=1;i<k;i++){printf("%s", a[i])}; printf("\n")}' rsa.public 
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwn1iVC6HF4CZ16A/ddh8H6rPmG4P6scm/wExaCgHP4KEpPuKvUFX22CKbS4pHTD7Xo+YOjHM0+cgtGYyF1C/l/4m1OiKl1oGv3yjd8MWN85ufc2TIod9zzb4gmUm7D6HEfDWXg70myTma63ldCniG/nBFSObb7FBfTm0Q2cJfUQIDAQAB

root@mydomain.com: # dig +short TXT 202002._domainkey.mydomain.com
"v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwn1iVC6HF4CZ16A/ddh8H6rPmG4P6scm/wExaCgHP4KEpPuKvUFX22CKbS4pHTD7Xo+YOjHM0+cgtGYyF1C/l/4m1OiKl1oGv3yjd8MWN85ufc2TIod9zzb4gmUm7D6HEfDWXg70myTma63ldCniG/nBFSObb7FBfTm0Q2cJfUQIDAQAB"


DMARC
DMARC was introduced to prevent a spammer spoofing mail from a domain that has a DKIM record simply by not including any DKIM signing, In effect, it ensures that there are satisfactory SPF and DKIM records if the domain's admin claims they should be present.
root@mydomain.com: # dig +short TXT _dmarc.mydomain.com
"v=DMARC1; p=reject; adkim=s; aspf=s; ruf=mailto:david@mydomain"
The second, policy field could also be either none or quarantine. The last 3 fields are optional and the individual control of SPF and DKIM handling, can be either strict as above, or relaxed r. In the last field rua requests reports in a digest as oppossed to ruf (individual failure reports).

As well as the commands indicated above to test these settings there are now a plethora of online sites that will run tests for you. While your at it, make sure you have not inadvertently created an open relay out of your mail exchanger.

ufw and fail2ban

For firewalling, install the ufw and fail2ban packages must be installed. There's plenty of information devoted to the ufw firewall elsewhere. Refer to that to make your firewall look something like this:-
root@mydomain.com: # ufw status
	/\/\/\/\/\/\/\/\/\/\/\
2222                       ALLOW       x.x.x.x/24              
2222                       DENY        Anywhere                  
25                         ALLOW       Anywhere                  
80                         ALLOW       Anywhere                  
443                        ALLOW       Anywhere                   
80 (v6)                    ALLOW       Anywhere (v6)             
443 (v6)                   ALLOW       Anywhere (v6)             
Brief explanation: I run ssh on port 2222 (actually pretty pointless :-) and the table starts with a list of allowed address such as home broadband and library wifi before the DENY rule. This (the ALLOW rules followed by DENY, not the switch from port 22) is a very effective way of guarding shell access to the server; the only other thing I'd recommend is disallowing login by the root user. The important entry for us here is the ALLOW rule for port 25 as exim4 will be listening there. If you were using ipv6 you'd need an additional rule for port 25. The other rules will be touched on later.

The addition of fail2ban creates a dynamic firewall; bad behaviour on your port 25 will result in offenders being blocked for a time set to suit your pleasure. But a warning; I know of one VPS provider where although a fail2ban block and the resulting iptables rule expire as scheduled, nevertheless a block remains until the machine is rebooted. Bear that in mind if you hit a problem with a genuine hotmail or gmail user being unable to reach you. To continue, create a /etc/fail2ban/jail.local file something like this:-

[DEFAULT]
ignoreip = x.x.x.x x.x.x.x/24
bantime = 2h
usedns = no
findtime = 15m
maxretry = 1
bantime.increment = true
bantime.factor = 1
bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
action = %(action_)s

[exim]
# see filter.d/exim.conf for further modes supported from filter:
#mode = normal
port   = 25
logpath = /var/log/exim4/rejectlog
enabled = true

[sshd]
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
enabled = false
The DEFAULT section applies to all jails unless any of its settings are overriden in them. A space seperated list of ips and ranges is ignored, in effect a whitelisting. The maxretry setting will get bad behaviour banned immediately for 2 hours, so findtime, the interval between attacks when maxretry is set higher, does not come into play. Further offences after 2 hours will lead to longer bans. The ssh jail is included only because it is enabled by default and I merely want to disable it due to the other strategy I have mentioned being in place.

At this point we can actually make our server live! Just make sure the exim4 settings have been updated and start or restart it. If you log into the server over ssh, you'll be able to read and send email using a cli program such as mutt. I'm not recommending you rest yet though as I want to add imap and webmail access for a more convenient experience.

dovecot

Install the dovecot-imapd package; this will allow us to access our mail server using the imap, or preferably imaps protocol. The mail storage format must match that of exim4, but this being Debian, mbox is the default. As a system user you should be able to authenticate to dovecot with your usual password; we can test that with telnet. Note that since we are testing with telnet locally and will be using webmail rather than a desktop email client, neither port 143 or 993 need to be accessible from outside.
david@mydomain.com:~ $ telnet localhost 143
Trying 127.0.0.1...
Connected to eden.
Escape character is '^]'.
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ STARTTLS AUTH=PLAIN] Dovecot (Debian) ready.
A1 LOGIN eve 'password'
A1 OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY
THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT
CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN
CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY STATUS=SIZE SAVEDATE LITERAL+ NOTIFY SPECIAL-USE]
Logged in A2 LOGOUT * BYE Logging out A2 OK Logout completed (0.001 + 0.000 secs). Connection closed by foreign host. david@mydomain.com:~ $
I know of a hopefully rare instance when that will not work, which occurs if you use fscrypt to encrypt partitions. Such a problem can be fixed by editing the file /etc/dovecot/conf.d/10-master.conf and then restarting dovecot.
# Default VSZ (virtual memory size) limit for service processes. This is mainly
# intended to catch and kill processes that leak memory before they eat up
# everything.
#default_vsz_limit = 256M
default_vsz_limit = 4096M #added to fix fscrypt incompatibilty
With our production setup we will want to use encryption, so we want to switch from plain imap access to encrypted imaps. As with exim4, Debian provides a shell script to generate a SSL certificate and key.
root@mydomain.com:~# cd /usr/share/dovecot/
root@mydomain.com:/usr/share/dovecot# ./mkcert.sh

The script must be run from it's own directory to find library files it needs to call. The necessary files may have been generated by the install process, in which case the script will inform you of that. Either way there should now be a subdirectory /etc/dovecot/ssl/ with files dovecot.pem and dovecot.key

In /etc/dovecot/conf.d/10-ssl.conf (the < characters are not a typo!):-

# SSL/TLS support: yes, no, required.
#ssl = no 
ssl = yes
ssl_cert = </etc/dovecot/ssl/dovecot.pem
ssl_key = </etc/dovecot/ssl/dovecot.key
Restart dovecot and check that imaps is available on port 993
openssl s_client -servername localhost -connect localhost:993
/\/\/\/\/\/\
    output of certificates removed
\/\/\/\/\/\/
* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN] Dovecot ready.

java and tomcat

Since I want to use a java webapp for webmail access, we need a java runtime. I don't use Debian java packages, rather I unpack tarballs for jdk-21_linux-x64_bin.tar.gz and apache-tomcat-10.0.13.tar.gz into the
/opt directory. I rename to /opt/tomcat and make that whole directory tree owned by a limited user rather than root.The java development kit contains a large bundle of code we do not need to run tomcat and a webmail app so we will produce a slimmed down java runtime that will be less than a third compared to the jdk:-
root@mydomain.com:~ # /opt/jdk-21.0.1/bin/jlink --add-modules java.base,java.logging,java.rmi,java.desktop,java.security.sasl,java.xml,java.management,java.naming,java.sql,java.instrument,java.security.jgss,
jdk.crypto.cryptoki,java.transaction.xa,java.compiler --output jre-21.0.1 --no-header-files --no-man-pages --strip-debug
The tarballs and the original jdk-21.0.1 directory can be deleted as we are going to configure tomcat to use our jre-21.0.1 version of java. That java will need the dovecot certificate to work with the encrypted imaps protocol:-
root@mydomain.com:~ # /opt/jre-21.0.1/bin/keytool -import -alias dovecot -keystore /opt/jre-21.0.1/lib/security/cacerts -file /etc/dovecot/ssl/dovecot.pem
Enter keystore password:
This command will copy the dovecot certificate into java's certificate store. If you haven't changed it, the password will be changeit.

We are going to run tomcat as a stand alone webserver; if you want to run apache2, the old write up details how to configure tomcat as a back end rather than itself listening on ports 80 and 443. We do not want to expose a root instance of tomcat so we need to install authbind and comment out and add to the bottom of /opt/tomcat/bin/startup.sh.

#--CHANGED-----------------------------
#exec "$PRGDIR"/"$EXECUTABLE" start "$@"
exec authbind --deep "$PRGDIR"/"$EXECUTABLE" start "$@"
Then create an executable file /opt/tomcat/bin/setenv.sh with this content:-
#! /bin/sh
JRE_HOME="/opt/jre-21.0.1"
JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStore='/opt/jre-21.0.1/lib/security/cacerts'"
JAVA_OPTS="$JAVA_OPTS -Djakarta.activation.debug=true"

CATALINA_OPTS="$CATALINA_OPTS -Xms64m"
CATALINA_OPTS="$CATALINA_OPTS -Xmx512m"
CATALINA_OPTS="$CATALINA_OPTS -XX:+UseParallelGC"
CATALINA_OPTS="$CATALINA_OPTS -XX:MaxGCPauseMillis=1500"
CATALINA_OPTS="$CATALINA_OPTS -server"
CATALINA_OPTS="$CATALINA_OPTS -XX:+DisableExplicitGC"

if [ -r "$CATALINA_BASE/bin/appenv.sh" ]; then
  . "$CATALINA_BASE/bin/appenv.sh"
fi

echo "Using CATALINA_OPTS:"
for arg in $CATALINA_OPTS
do
    echo "  " $arg
done

echo "Using JAVA_OPTS:"
for arg in $JAVA_OPTS
do
    echo "  " $arg
done
We need to make some changes to tomcat configuration, to allow it to listen on the https port 443 and to prepare it for the webapp it is going to run. Carefully edit the conf/server.xml file, ensuring additions go in the correct place:-
      	      <!--CHANGED added for jwma's database storage*********-->	             
      	      <Resource name="jdbc/jwmaDB"
              type="javax.sql.DataSource"  auth="Container"
              description="Derby database for jwma"
              maxTotal="8" maxIdle="30" maxWaitMillis="-1"
              username="" password="" 
              driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
              url="jdbc:derby:Databases/jwmaDB"/> 
  </GlobalNamingResources>

  <!--UNCOMMENT and add-->
  <Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">>
        <SSLHostConfig> 
		<Certificate
			certificateKeystoreFile="./conf/bundle.pfx" 
			certificateKeystorePass="changeit"
           		clientAuth="false" sslProtocol="TLS" keystoreType="PKCS12"/>
        </SSLHostConfig>
  </Connector>
        
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
	
	<!--CHANGED added -->
	<Context docBase="/opt/tomcat/mta-sts/.well-known/" path="/.well-known" />
	<Context docBase="/opt/tomcat/contact" path="/contact" />
Were almost ready to start our tomcat server; to ensure it always starts after a reboot, edit or create an executable file /etc/rc.local, remember that a limited user (david in this example) needs to exist on the server and own the /opt/tomcat directory tree.
#!/bin/sh -e
#start tomcat with authbind
cd /opt/tomcat
su david -c "bin/startup.sh"
exit 0
We should also add to our fail2ban set up to guard against attacks; incidentally, my experience is you get much less bad behaviour on the http/https ports with tomcat listening as opposed to apache2. Nevertheless, create /etc/fail2ban/filter.d/tomcat.local:-
[INCLUDES]
before = common.conf

[Definition]
# 1. match on 40x http status code
# 2. URLs should start with a forward slash - (often proxy requests start with http://blahh)
# 3. match on http 1.0 - let's not support it, even for search engines

failregex =  - - \[.*\] "GET .* HTTP/1.1" 40\d \d+$
              - - \[.*\] "GET http
              - - \[.*\] "GET .* HTTP/1.0"

ignoreregex =

#https://gist.github.com/hespresati/e5e6ad67f407d8c7f666
and add this to our already created /etc/fail2ban/jail.local before restarting fail2ban:-
[tomcat]
enabled = true
port = 80,443
filter = tomcat
logpath = /opt/tomcat/logs/localhost_access_log.*.txt
maxretry = 2

Letsencrypt

Install the certbot package. Notice the Certificate section in the tomcat server.xml file above. Although there's plenty of information devoted to getting and maintaining a letsencrypt TLS certificates elsewhere, we will need to adapt the certificate so that it can be used by tomcat to verify and secure our mydomain.com domain where our webmail app will be running. These are the commands that should be run when the certificate is obtained and each time it is renewed; note that some must be run by user root and some by our limited user:-
root@mydomain.com: /etc/letsencrypt/live/caudwell.org.uk/ # openssl pkcs12 -export -out bundle.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem -password pass:changeit
root@mydomain.com: /etc/letsencrypt/live/caudwell.org.uk/ # chown david:david bundle.pfx
root@mydomain.com: /etc/letsencrypt/live/caudwell.org.uk/ # mv bundle.pfx ~tomcat/conf/

david@mydomain.com: /opt/tomcat/ $ bin/catalina.sh stop
david@mydomain.com: /opt/tomcat/ $ bin/startup.sh
/pre>

jwma

JWMA is the webmail webapp that you can
download to the /opt/tomcat/webapps/ directory. It will start up automatically and create a config file in /opt/tomcat/.jwma. Unfortunately it uses Maildir by default (what was I thinking?) rather than mbox, so edit the file jwma.config to suit; since our dovecot is imaps ready you can also switch to that on port 993. With the changes made and tomcat stopped and started as above in the tomcat section, if like the david in this write up, you have a shell account on the system, you should be able to login (just use your user name/password *not* an email address), read and send email and tweak you're personal jwma configuration. Please refer to the page above for copious information, including links to more detail of the tomcat and java tweaks.

blocklists

Sadly, it's quite possible your ipv4 address is in one or more blocklists before you even start. As I've descibed already, unless you have a whole /64 ipv6 range there's likely nothing for it other than to not use ipv6. There's a number of blocksite checking pages on line. My experience that providing the bad behaviour is in the past, you should have no problem getting yourself removed.

Microsoft have a private list for their outlook and hotmail domains, but I was pleasantly surprised that you can get to email an actual human and will probably find him/her to be entirely reasonable. Googlemail and gmail are the worst that I'm still struggling with regarding receiving mail from those domains.

Here's a horror strory from the past, at a time when I did control a full ipv6 /64. I'd changed my MX's AAAA record from xxxx::xx35 to xxxx::xx45. DNS had updated everywhere, I even checked each of google's own name servers. Everyone had the new correct address, but gmail insisted it was wrong. Doh! I just switched back to the original address and then everything worked again once DNS updated world wide.