updated long ago, so way out of date, but may still be helpful

the perfect java email server

How to set up an almost entirely java based email server, with smtp, imap/imaps and webmail access. Note that although this was all thoroughly tested only on linux servers, it ought to work just as well on that other operating system.

Accessing this server with java based webmail is dealt with here.

A note on versions

This writeup is based on the apache james server 3.3.0 version. Not the latest release, but at the time of writing there appeared to be problems with version 3.4.0. The 3.3.0 version of james needs a java 8 runtime; it does not for instance work with java 11.

Starting james

After downloading james from the link above, unzip the archive in a suitable place - on a linux server /opt is a reasonable choice. There are a number of scripts in it's bin directory; I recommend using the run.sh command (there's a run.bat for windows):-

root@skaro # cd /opt/james-server-app-3.3.0/bin/
root@skaro # nohup ./run.sh &

I have a couple of reasons for favouring the use of run.sh over the james command. Firstly I found that although james start and james console works fine on a fedora linux system, it fails in a way mysterious to me on debian. Using run.sh offers an easy way to set the appropriate version of java to use. in /opt/james-server-app-3.3.0/conf create an executable file setenv.sh (on windows setenv.bat) with content something like

JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.fc29.x86_64/jre".

The james command does not seem to reference setenv.sh, but alternatively the JAVA_HOME can be set as an environmental variable in whatever way your OS recommends.

James must be started by the root user (administrator on windows) as it needs access to priviledged ports below 1000; you must first ensure that no other services are listening on the smtp and imap/imaps ports. It must be stopped and restarted whenever it's configuration files are changed. A linux way of doing this is suggested below:-

root@skaro # ps aux | grep james
root      2427  108  9.9 3214224 389752 pts/0  Sl   12:18   0:52 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0
/\/\/\/\/\/\/\
	output snipped
\/\/\/\/\/\/\/
root@skaro # kill -9 2427
root@skaro # nohup ./run.sh &

Configuring maibox storage

The default for email storage is to use the embedded derby database. On a linux system maildir is an alternative, this is configured in the mailbox.xml file.

Ajusting the smtp server

This is done by editing the smtpserver.xml file. I'd like to enable socketTLS, but my jwma webmail app doesn't like that at the moment and mail doesn't get sent from it.

I uncommented the SMTP authentication code, changing the value from true to announce.

I uncommented the DNSRBLHandler code, but commented out the whitelist and replaced the DNSBL databases to use sbl-xbl.spamhaus.org, bl.spamcop.net and cbl.abuseat.org. Don't neglect to leave the . after each one.

Uncommenting the SPFHandler code looks like a good idea, but for me it stops mail being delivered.

I uncommented the SpamAssassinHandler code and adjusted down spamdRejectionHits from 10 to 4 (I'm guessing this refers to the spamassassin score). There are some more notes on spamassassin here.

Ajusting the imap server

This is done by editing the imapserver.xml file and this is as good a point as any to mention that I do not want to support pop3, so I set pop3server enabled to false in the pop3server.xml file.

Rather than unencrypted imap, I only want to offer imaps and for that several steps are necessary. Firstly this line

<bind>0.0.0.0:143</bind>

is changed from port 143 to 993. The tls socketTLS is set to true and key and self signed certificate are generated; the linux way of doing this is as follows (I believe there is also a openssl version for windows):-

keytool -genkey -alias james -keyalg RSA -keystore /opt/james-server-app-3.3.0/conf/keystore
keytool -selfcert -alias james -keystore /opt/james-server-app-3.3.0/conf/keystore

I've found this technology to be very fragile. As well as imaps failing if the wrong version of java is used by a java webmail client as mentioned in the webmail client notes, it also does not work if the key is created by the root user and if permissions and ownership are messed with after the commands are run.

The first command asks for a password, which must match what you enter as <secret>.

I ignore the other questions except for

What is the name of your organization?

where I enter the domain name of the server. Do not enter a second password for the james certificate and do not convert the keystore from JKS to pkcs12.

The final step is to add a provider to the conf/lib folder and configure the <provider> option to either be

org.bouncycastle.jce.provider.BouncyCastleProvider, getting the jar from here

or com.sun.crypto.provider and downloading here.

You can check that this has worked on a linux system with the openssl command:-

root@skaro # openssl s_client -servername localhost -connect localhost:993
CONNECTED(00000003)
/\/\/\/\/\/\/\/\/\/\/
	certificate details snipped
\/\/\/\/\/\/\/\/\/\/\
---
* OK JAMES IMAP4rev1 Server  Server skaro is ready.

Implementing DKIM and adjusting the mailetcontainer.xml

DKIM is one of three technologies that are becoming important to ensure that the mega providers such as hotmail and gmail deliver our email to inboxes rather than junk folders. It's implemented in two stages; firstly james must be configured to sign outgoing emails as explained next. The second stage involves creating a TXT record for the domain's DNS and that is explained on the email authentication page. What follows is closely based on the excellent information at nozaki.me.

Unlike Kohei Nozaki, I choice to use a binary version of jdkim, which you can fetch from here. Since unlike gmail, hotmail etc, I don't bother to check incoming DKIM signatures, only three of the jars from the project are necessary. Unzip the archive and put apache-jdkim-library-0.2.jar, apache-jdkim-mailets-0.2.jar and not-yet-commons-ssl-0.3.11.jar into /opt/james-server-app-3.3.0/conf/lib.

Next job is to generate the public key, which you'll need to add to your domain's DNS and the corresponding private key which james will use to sign outgoing email:-

root@skaro # cd /opt/james-server-app-3.3.0/conf/lib
root@skaro # openssl genrsa -out dkim-private.pem 1024
Generating RSA private key, 1024 bit long modulus (2 primes)
............................................+++++
.............................................+++++
e is 65537 (0x010001)

root@skaro # openssl rsa -in dkim-private.pem -out dkim-public.pem -pubout
writing RSA key
Place the following code block in the mailetcontainer.xml file immediately before the RemoteDelivery mailet:-
<!-- DKIM signing -->
<mailet match="All" class="org.apache.james.jdkim.mailets.ConvertTo7Bit"/>
		
<mailet match="All" class="org.apache.james.jdkim.mailets.DKIMSign">
	<signatureTemplate>v=1; s=your_selector; d=your_domain; c=relaxed/relaxed; h=Message-ID:Date:Subject:From:To:MIME-Version:Content-Type; a=rsa-sha256; bh=; b=;</signatureTemplate>
	<privateKey>
		-----BEGIN RSA PRIVATE KEY-----
contents of your dkim-private.pem here
		-----END RSA PRIVATE KEY-----
	</privateKey>
</mailet>
your_selector is dealt with on the email authentication page and your_domain should be the domain that james is signing email for. Then within the RemoteDelivery mailet add

<mail.smtp.allow8bitmime>false</mail.smtp.allow8bitmime>

There are other changes to be made in the default mailetcontainer.xml that do not relate to DKIM signing. The <postmaster> line should be configured with a working email address in your domain. For tidyness that also applies to the <notice> section of the AttachmentFileNameIs mailet.

The mailet with match SenderIs can be used to whitelist known allowed users and blacklist unwanted senders. I assume that additional matches can be added as necessary. I comment out the ToSenderFolder mailet as the jwma webmail program that I use does this and we do not need to save two copies of each mail sent to an outbox. I also comment out the RemoteAddrNotInNetwork mailet as we are using SMTP auth. It's a good plan to check that your james is not acting as an open relay at the MXtoolbox site.

I uncomment the RecipientIsLocal mailet and set the mailbox name to Spam. My hope is I will not see too much in there!

Logging

The default logging system is sub-optimal and provided a log4j.properties file that much improves the situation despite it being intended for version 3.4.0 of james. Simply put it in the conf directory and restart james.