Skip to content

orel33/local-mail-agent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Local Mail Agent

This repository contains Dockerfile and configuration files for a Docker image, that runs a local-only mail agent on Linux (Debian 12). This image is published in the Docker Hub. Besides, this repository contains scripts to build & run this image.

To run this image, simply use:

$ docker run -it --hostname=pouet.com orel33/local-mail-agent

In our case, the --hostname option is really important because the chosen hostname will also be used as the mail domain name (or mailname). In the following, we will assume that the chosen hostname is pouet.com.

Note that our mail agent is said to be local because sending mail to remote domains is not supported.

In few words

More precisely, this Dockerized mail agent consists of two servers:

  • an SMTP server (Exim4) listening on ports 25 (plaintext) and 465 (TLS),
  • a POP3 server (Dovecot) listening on ports 110 (plaintext) and 995 (TLS).

Nota Bene: The server that lets you send mail is called an outgoing server, or SMTP server. The server that lets you receive mail is called an incoming server, or POP3 server.

Both servers are configured to work with or without a secure TLS connection (snakeoil certificate), with or without authentication (using login).

For the purposes of the demo, the Docker image has two user accounts toto (password toto) and tutu (password tutu), associated with email accounts toto@pouet.com and tutu@pouet.com respectively. In this local-only configuration, the pouet.com domain is fictitious, and can only be used locally on the Docker machine.

In short, the user toto (toto@pouet.com) can send an email to the user tutu (tutu@pouet.com) via the SMTP protocol. And symmetrically, tutu can receive this email via the POP3 protocol.

As shown in the figure below, the Mail User Agent (MUA) is the program that acts as a SMTP & POP3 client for end-users, allowing them to send and receive email by connecting to our Local Mail Agent (LMA), which acts as the central server for all users of the pouet.com domain.

flowchart LR;
    subgraph "Mail User Agent"
        SMTPC("Client SMTP");
        POP3C("Client POP3");
    end
    subgraph "Local Mail Agent"
        SMTPS("SMTP Server");
        POP3S("POP3 Server");
        MX[("Mailboxes\n /var/mail/")];
    end
    SMTPC-- SMTP --> SMTPS;
    POP3C-- POP3 --> POP3S;
    SMTPS & POP3S <--> MX;

For each user, both servers are linked locally to the same mailbox, which is stored in the /var/mail/ directory in mbox format. This mailbox can be accessed directly, by logging into the user account on the Docker machine, and using a command-line mail client, such as mutt or mail.

Launching Docker

The advantage of this Docker image is that it allows you to launch our local mail agent in a container without root privileges, or having its own domain name (DNS). By the way, if you change the configuration of the servers in the Docker container, there's no risk of breaking anything in the host system.

Let's start by launching the Docker image.

$ docker run -it --hostname=pouet.com orel33/local-mail-agent

You are logged in as root in the Docker container. Check with netstat that the servers have started successfully...

root@pouet$ netstat -tlpn
Proto Local Address     Foreign Address    State     Program name
tcp   0.0.0.0:25        0.0.0.0:*          LISTEN    exim4
tcp   0.0.0.0:465       0.0.0.0:*          LISTEN    exim4
tcp   0.0.0.0:110       0.0.0.0:*          LISTEN    dovecot
tcp   0.0.0.0:995       0.0.0.0:*          LISTEN    dovecot
root@pouet$

Great! Now, let's send an email from tutu@pouet.com to toto@pouet.com by using the mail command. But first, you need to log in as the 'tutu' user within the container.

# send mail from toto to tutu
root@pouet$ su toto
toto@pouet$ echo "Testing message." | mail -s "test" tutu@pouet.com
toto@pouet$ exit
# recv mail as tutu
root@pouet$ su tutu
tutu@pouet$ mail
"/var/mail/tutu": 1 message 1 new
>N   1 toto@pouet.com     Fri Nov 10 11:47  16/462   test
? q
tutu@pouet$ exit
root@pouet$

Simply type exit as root to exit the Docker container.

You can find server logs here:

  • /var/log/dovecot.log
  • /var/log/exim4/mainlog

Test Outside Docker

Now let's try using our mail agent outside the Docker container.

$ docker run -it --hostname=pouet.com -p 10025:25 -p 10465:465 -p 10110:110 -p 10995:995 orel33/local-mail-agent
root@pouet:/home/docker#

Indeed, it is possible to make both the SMTP & POP3 servers available outside of the Docker world, listening on alternative ports. To do this, we use the option -p x:y, which makes a docker service listening on port y, accessible on the host machine via the port x.

These options expose and map ports between the host machine and the container. In this case:

  • Port 10025 on the host is mapped to port 25 in the container (SMTP).
  • Port 10465 on the host is mapped to port 465 in the container (SMTP over TLS)
  • Port 10110 on the host is mapped to port 110 in the container (POP3).
  • Port 10995 on the host is mapped to port 995 in the container (POP3 over TLS).

Thus, it is possible to connect the Docker SMTP server (port 25) outside from the container by using Telnet, as follows:

$ telnet localhost 10025

This is particularly convenient to develop and test a mail user agent (MUA), that implements clients for both SMTP & POP3 servers.

Telnet Session

Let's assume that the Docker container is already running on the ssss machine and that we are connected to the cccc machine, which may be ssss itself. Now, let's send an email from toto@pouet.com to tutu@pouet.com. For this demo, we just use a Telnet session (by hand) that connects to the SMTP server (ssss:10025). In this case, we use an unsecure connection without any authentication.

Here is the log of this Telnet session. The symbols > and < are used to distinguish between lines of text sent or received over the network.

cccc$ telnet ssss 10025
Connected to ssss.
Escape character is '^]'.
< 220 pouet.com ESMTP Exim 4
> EHLO pouet.com
< 250-pouet.com Hello pouet.com
> MAIL FROM: <toto@pouet.com>
< 250 OK
> RCPT TO: <tutu@pouet.com>
< 250 Accepted
> DATA
< 354 Enter message, ending with "." on a line by itself
> Subject: Test
> From: <toto@pouet.com>
> To: <tutu@pouet.com>
> Testing message.
> .
< 250 OK
> QUIT
< 221 pouet.com closing connection
Connection closed by foreign host.

Let's now retrieve this email by using a Telnet session that connects to the POP3 server (ssss:10110). In this case, we still use an unsecured connection, but with authentication as shown on this log.

cccc$ telnet ssss 10110
Connected to ssss.
< +OK Welcome on Dovecot.
> USER tutu
< +OK
> PASS tutu
< +OK Logged in.
> STAT
< +OK 1 381
> LIST
< +OK 1 messages:
< 1 381
< .
> RETR 1
> +OK 381 octets
< From: <toto@pouet.com>
< To: <tutu@pouet.com>
< Subject: Test
<
< Testing message.
< .
> QUIT
< +OK Logging out.
Connection closed by foreign host.

TLS Session

Basically, you can reproduce the Telnet session described just before by using a secure connection over SSL/TLS with the openssl command, as follows.

  • For SMTP over TLS (port 465):
$ openssl s_client -quiet -crlf -connect localhost:465
220 pouet.com ESMTP Exim 40

The option -quiet is a workaround, which suppresses the interactive interpretation of R and Q characters by openssl.

  • For POP3 over TLS (port 995):
$ openssl s_client -quiet -crlf -connect localhost:995
+OK Welcome on Dovecot.

For both SMTP and POP3 servers, we use in this demo a self-signed certifcate named snakeoil and available on Debian distribution: /etc/ssl/certs/ssl-cert-snakeoil.pem. Obviously, a legagy mail user agent will not trust it. So, in order to use our local mail agent, it may require to disable the certificate verification in your client.


aurelien.esnard@u-bordeaux.fr

About

Local Mail Agent (local-only Exim4 SMTP Server and Dovecot POP3 Server)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published