re-order pages. add page on lmtp.
This commit is contained in:
parent
b97d7b03da
commit
759ed36026
5 changed files with 215 additions and 53 deletions
24
src/content/docs/ispmail-trixie/156-overview.mdx
Normal file
24
src/content/docs/ispmail-trixie/156-overview.mdx
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
title: Big picture
|
||||||
|
lastUpdated: 2025-08-24
|
||||||
|
slug: ispmail-trixie/big-picture
|
||||||
|
sidebar:
|
||||||
|
order: 156
|
||||||
|
---
|
||||||
|
|
||||||
|
import "@splidejs/splide/css";
|
||||||
|
import { Splide, SplideSlide } from "astro-splide";
|
||||||
|
|
||||||
|
I have created a slideshow to help you understand the process of receiving an email from a remote mail server. Hopefully
|
||||||
|
it helps to get a better understanding of the steps involved in receiving email. We will prepare the necessary
|
||||||
|
configuration in the next chapters.
|
||||||
|
|
||||||
|
Use the arrows to navigate between slides:
|
||||||
|
|
||||||
|
<Splide>
|
||||||
|
{Array.from({ length: 24 }, (_, i) => i + 1).map((i) => (
|
||||||
|
<SplideSlide key={i}>
|
||||||
|
<img src={`/big-picture-receive/${String(i).padStart(2, "0")}.svg`} alt={`Slide ${i}`} />
|
||||||
|
</SplideSlide>
|
||||||
|
))}
|
||||||
|
</Splide>
|
||||||
|
|
@ -8,32 +8,12 @@ sidebar:
|
||||||
|
|
||||||
import { Aside } from "@astrojs/starlight/components";
|
import { Aside } from "@astrojs/starlight/components";
|
||||||
|
|
||||||
import "@splidejs/splide/css";
|
|
||||||
import { Splide, SplideSlide } from "astro-splide";
|
|
||||||
|
|
||||||
import { Steps } from "@astrojs/starlight/components";
|
import { Steps } from "@astrojs/starlight/components";
|
||||||
|
|
||||||
import Box from "../../../components/Box.astro";
|
import Box from "../../../components/Box.astro";
|
||||||
|
|
||||||
import StepListReceive from "../../../components/StepListReceive.astro";
|
import StepListReceive from "../../../components/StepListReceive.astro";
|
||||||
|
|
||||||
I have created a slideshow to help you understand the process of receiving an email from a remote mail server. Use the
|
|
||||||
arrows to navigate between slides:
|
|
||||||
|
|
||||||
<Splide>
|
|
||||||
{Array.from({ length: 24 }, (_, i) => i + 1).map((i) => (
|
|
||||||
<SplideSlide key={i}>
|
|
||||||
<img src={`/big-picture-receive/${String(i).padStart(2, "0")}.svg`} alt={`Slide ${i}`} />
|
|
||||||
</SplideSlide>
|
|
||||||
))}
|
|
||||||
</Splide>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Let's tackle the receiving of emails step by step:
|
|
||||||
|
|
||||||
## DNS
|
|
||||||
|
|
||||||
<StepListReceive currentStep={1} />
|
<StepListReceive currentStep={1} />
|
||||||
|
|
||||||
As shown in the slideshow, you need to have proper DNS records set up. Say that you want to receive emails for the
|
As shown in the slideshow, you need to have proper DNS records set up. Say that you want to receive emails for the
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
title: "Receive emails: Postfix"
|
title: "Postfix"
|
||||||
lastUpdated: 2025-08-20
|
lastUpdated: 2025-08-20
|
||||||
slug: ispmail-trixie/receive-emails-postfix
|
slug: ispmail-trixie/postfix
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 160
|
order: 160
|
||||||
---
|
---
|
||||||
|
|
@ -48,7 +48,7 @@ SELECT "yes" FROM virtual_domains WHERE name='example.net'
|
||||||
Run the following code in your shell to create a configuration file creating that mapping:
|
Run the following code in your shell to create a configuration file creating that mapping:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cat > /etc/postfix/virtual-mailbox-domains.cf << EOF
|
cat > /etc/postfix/mariadb-virtual-mailbox-domains.cf << EOF
|
||||||
user = mailserver
|
user = mailserver
|
||||||
password = SECOND-PASSWORD-HERE
|
password = SECOND-PASSWORD-HERE
|
||||||
hosts = 127.0.0.1
|
hosts = 127.0.0.1
|
||||||
|
|
@ -82,7 +82,7 @@ Apparently, there aren't any more. So the email will go to `john@example.org`.
|
||||||
Run this code to create the appropriate mapping file:
|
Run this code to create the appropriate mapping file:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cat > /etc/postfix/virtual-alias-maps.cf << EOF
|
cat > /etc/postfix/mariadb-virtual-alias-maps.cf << EOF
|
||||||
user = mailserver
|
user = mailserver
|
||||||
password = SECOND-PASSWORD-HERE
|
password = SECOND-PASSWORD-HERE
|
||||||
hosts = 127.0.0.1
|
hosts = 127.0.0.1
|
||||||
|
|
@ -98,7 +98,7 @@ The query now gets all the `destination` email addresses from the database for a
|
||||||
The last mapping we need is a query to find valid mailboxes. Without further ado:
|
The last mapping we need is a query to find valid mailboxes. Without further ado:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cat > /etc/postfix/virtual-mailbox-maps.cf << EOF
|
cat > /etc/postfix/mariadb-virtual-mailbox-maps.cf << EOF
|
||||||
user = mailserver
|
user = mailserver
|
||||||
password = SECOND-PASSWORD-HERE
|
password = SECOND-PASSWORD-HERE
|
||||||
hosts = 127.0.0.1
|
hosts = 127.0.0.1
|
||||||
|
|
@ -120,12 +120,12 @@ sufficient here.
|
||||||
You have created the config files for the three mappings. Now you just need to tell Postfix to use them:
|
You have created the config files for the three mappings. Now you just need to tell Postfix to use them:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
postconf virtual_mailbox_domains=mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
|
postconf virtual_mailbox_domains=mysql:/etc/postfix/mariadb-virtual-mailbox-domains.cf
|
||||||
postconf virtual_mailbox_maps=mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
|
postconf virtual_mailbox_maps=mysql:/etc/postfix/mariadb-virtual-mailbox-maps.cf
|
||||||
postconf virtual_alias_maps=mysql:/etc/postfix/mysql-virtual-alias-maps.cf
|
postconf virtual_alias_maps=mysql:/etc/postfix/mariadb-virtual-alias-maps.cf
|
||||||
|
|
||||||
chown root:postfix /etc/postfix/*.cf
|
chown root:postfix /etc/postfix/mariadb-*.cf
|
||||||
chmod o= /etc/postfix/*.cf
|
chmod o= /etc/postfix/mariadb-*.cf
|
||||||
```
|
```
|
||||||
|
|
||||||
`postconf` is a command that changes configuration in `/etc/postfix/main.cf` and applies them instantly. You don't have
|
`postconf` is a command that changes configuration in `/etc/postfix/main.cf` and applies them instantly. You don't have
|
||||||
|
|
@ -139,9 +139,9 @@ access. After all a database password is found in these files.
|
||||||
Give the mappings a quick test using the `postmap -q` command (_q_ stands for _query_):
|
Give the mappings a quick test using the `postmap -q` command (_q_ stands for _query_):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
postmap -q example.org mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
|
postmap -q example.org mysql:/etc/postfix/mariadb-virtual-mailbox-domains.cf
|
||||||
postmap -q jack@example.org mysql:/etc/postfix/mysql-virtual-alias-maps.cf
|
postmap -q jack@example.org mysql:/etc/postfix/mariadb-virtual-alias-maps.cf
|
||||||
postmap -q john@example.org mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
|
postmap -q john@example.org mysql:/etc/postfix/mariadb-virtual-mailbox-maps.cf
|
||||||
```
|
```
|
||||||
|
|
||||||
These three commands use the three mapping files (`*.cf`) to query your three database tables. The result should show:
|
These three commands use the three mapping files (`*.cf`) to query your three database tables. The result should show:
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
title: "Deliver emails: Dovecot"
|
title: "Dovecot"
|
||||||
lastUpdated: 2025-08-22
|
lastUpdated: 2025-08-24
|
||||||
slug: ispmail-trixie/deliver-emails-dovecot
|
slug: ispmail-trixie/dovecot
|
||||||
sidebar:
|
sidebar:
|
||||||
order: 165
|
order: 165
|
||||||
---
|
---
|
||||||
|
|
@ -9,19 +9,7 @@ sidebar:
|
||||||
import { Aside } from "@astrojs/starlight/components";
|
import { Aside } from "@astrojs/starlight/components";
|
||||||
import StepListReceive from "../../../components/StepListReceive.astro";
|
import StepListReceive from "../../../components/StepListReceive.astro";
|
||||||
|
|
||||||
## About LMTP
|
<StepListReceive currentStep={4} />
|
||||||
|
|
||||||
<StepListReceive currentStep={3} />
|
|
||||||
|
|
||||||
As explained in the previous section, Postfix speaks SMTP and receives the email from the internet. Postfix could even
|
|
||||||
save the email to a mailbox on disk. But instead we will use Dovecot for the final delivery. Actually Dovecot's main
|
|
||||||
purpose is to let users fetch their email using the IMAP protocol. But it provides additional features we can use as
|
|
||||||
well.
|
|
||||||
|
|
||||||
So we need tell Postfix to hand over the incoming email to Dovecot. The communication between Postfix and Dovecot will
|
|
||||||
happen using LMTP – the [local mail transfer protocol](https://en.wikipedia.org/wiki/Local_Mail_Transfer_Protocol).
|
|
||||||
LMTP is a variant of SMTP with fewer features. It is meant for email communication between internal services that trust
|
|
||||||
each other.
|
|
||||||
|
|
||||||
In this chapter we will mainly configure Dovecot so that it knows how to deliver incoming emails.
|
In this chapter we will mainly configure Dovecot so that it knows how to deliver incoming emails.
|
||||||
|
|
||||||
|
|
@ -75,6 +63,8 @@ located, who owns them and what is their layout? Set this:
|
||||||
mail_driver = maildir
|
mail_driver = maildir
|
||||||
mail_home = /var/vmail/%{user | domain}/%{user | username}
|
mail_home = /var/vmail/%{user | domain}/%{user | username}
|
||||||
mail_path = ~/Maildir
|
mail_path = ~/Maildir
|
||||||
|
mail_uid = vmail
|
||||||
|
mail_gid = vmail
|
||||||
```
|
```
|
||||||
|
|
||||||
This looks more sophisticated than with versions of Dovecot before 2.4. What it means:
|
This looks more sophisticated than with versions of Dovecot before 2.4. What it means:
|
||||||
|
|
@ -87,9 +77,12 @@ This looks more sophisticated than with versions of Dovecot before 2.4. What it
|
||||||
- **mail_path**: Within the _home_ directory the actual mailbox will live in a subdirectory called `Maildir`. The reason
|
- **mail_path**: Within the _home_ directory the actual mailbox will live in a subdirectory called `Maildir`. The reason
|
||||||
is that we will store other data in the user's _home_ directory as well that should not conflict with the mailbox
|
is that we will store other data in the user's _home_ directory as well that should not conflict with the mailbox
|
||||||
directory.
|
directory.
|
||||||
|
- **mail_uid**/**mail_gid**/: All mailboxes are stored on disk under the owner _vmail_.
|
||||||
|
|
||||||
### 10-master.conf
|
### 10-master.conf
|
||||||
|
|
||||||
|
TODO: not needed. /var/run/dovecot/auth-userdb is created automatically.
|
||||||
|
|
||||||
This configuration file at `/etc/dovecot/conf.d/10-master.conf` deals with Dovecot's services.
|
This configuration file at `/etc/dovecot/conf.d/10-master.conf` deals with Dovecot's services.
|
||||||
|
|
||||||
So most settings are sane here and do not have to be changed. However one change is required in the “service auth”
|
So most settings are sane here and do not have to be changed. However one change is required in the “service auth”
|
||||||
|
|
@ -120,7 +113,17 @@ ssl_server_cert_file = /etc/letsencrypt/live/mail.example.org/fullchain.pem
|
||||||
ssl_server_key_file = /etc/letsencrypt/live/mail.example.org/privkey.pem
|
ssl_server_key_file = /etc/letsencrypt/live/mail.example.org/privkey.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
Next let’s take a look at how Dovecot knows about users and their passwords:
|
### 20-lmtp.conf
|
||||||
|
|
||||||
|
There is one setting in the `/etc/dovecot/conf.d/20-lmtp.conf` that will mess up the recipient's email address in our
|
||||||
|
setup. So please edit this file and comment out the `auth_username_format` line:
|
||||||
|
|
||||||
|
```
|
||||||
|
protocol lmtp {
|
||||||
|
#auth_username_format = %{user | username}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### auth-sql.conf.ext
|
### auth-sql.conf.ext
|
||||||
|
|
||||||
|
|
@ -142,7 +145,7 @@ userdb sql {
|
||||||
}
|
}
|
||||||
|
|
||||||
passdb sql {
|
passdb sql {
|
||||||
query = SELECT password FROM virtual_usrs where email='%{user}'
|
query = SELECT password FROM virtual_users where email='%{user}'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -220,8 +223,8 @@ That should give you:
|
||||||
|
|
||||||
```
|
```
|
||||||
field value
|
field value
|
||||||
uid
|
uid vmail
|
||||||
gid
|
gid vmail
|
||||||
home /var/vmail/example.org/john
|
home /var/vmail/example.org/john
|
||||||
mail_path /var/vmail/example.org/john/Maildir
|
mail_path /var/vmail/example.org/john/Maildir
|
||||||
```
|
```
|
||||||
155
src/content/docs/ispmail-trixie/167-lmtp.mdx
Normal file
155
src/content/docs/ispmail-trixie/167-lmtp.mdx
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
---
|
||||||
|
title: LMTP
|
||||||
|
lastUpdated: 2025-08-24
|
||||||
|
slug: ispmail-trixie/lmtp
|
||||||
|
sidebar:
|
||||||
|
order: 167
|
||||||
|
---
|
||||||
|
|
||||||
|
import { Aside } from "@astrojs/starlight/components";
|
||||||
|
import StepListReceive from "../../../components/StepListReceive.astro";
|
||||||
|
|
||||||
|
<StepListReceive currentStep={5} />
|
||||||
|
|
||||||
|
Glad to see that you are still with me. We are very close to receiving our first email. If you feel lost, please review
|
||||||
|
the [slideshow](/ispmail-trixie/big-picture/) from earlier in this guide.
|
||||||
|
|
||||||
|
As explained in the previous section, Postfix speaks SMTP and receives the email from the internet. Postfix could even
|
||||||
|
save the email to a mailbox on disk. But instead we will use Dovecot for the final delivery. Actually Dovecot's main
|
||||||
|
purpose is to let users fetch their email using the IMAP protocol. But it provides additional features we can use as
|
||||||
|
well.
|
||||||
|
|
||||||
|
So we need tell Postfix to hand over the incoming email to Dovecot. The communication between Postfix and Dovecot will
|
||||||
|
happen using LMTP – the [local mail transfer protocol](https://en.wikipedia.org/wiki/Local_Mail_Transfer_Protocol).
|
||||||
|
LMTP is a variant of SMTP with fewer features. It is meant for email communication between internal services that trust
|
||||||
|
each other.
|
||||||
|
|
||||||
|
## Dovecot listens to LMTP
|
||||||
|
|
||||||
|
There's nothing to do for you here. I just want to tell you how it works. By default Dovecot has this section in its
|
||||||
|
`/etc/dovecot/conf.d/10-master.conf` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
service lmtp {
|
||||||
|
unix_listener lmtp {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
So Dovecot has already put a socket into `/var/run/dovecot/lmtp` where it is ready to receive LMTP connections. A socket
|
||||||
|
is similar to a TCP port but it's only available for other processes running on same system. So nothing to do.
|
||||||
|
|
||||||
|
## Postfix talks to Dovecot using LMTP
|
||||||
|
|
||||||
|
The “_virtual_transport_” in Postfix defines the service to use for delivering emails to the local system. Dovecot has
|
||||||
|
created a socket file and is ready to listen to incoming LMTP connections. We just need to tell Postfix to send emails
|
||||||
|
there. So please run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
postconf virtual_transport=lmtp:unix:/var/run/dovecot/lmtp
|
||||||
|
```
|
||||||
|
|
||||||
|
The syntax looks crazy, but it’s actually simple. You just told Postfix to use the LMTP protocol. And that we want to
|
||||||
|
use a UNIX socket on the same system (instead of a TCP connection). And the socket file is located at
|
||||||
|
`/var/run/dovecot/lmtp`.
|
||||||
|
|
||||||
|
## Enable server-side mail rules
|
||||||
|
|
||||||
|
TODO: move to optional chapter
|
||||||
|
|
||||||
|
## Send a test mail locally
|
||||||
|
|
||||||
|
Finally we are ready for our first email. Using the `swaks` command you can create a test email to `john@example.org`
|
||||||
|
and send it to Postfix:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
swaks --server localhost --to john@example.org
|
||||||
|
```
|
||||||
|
|
||||||
|
If all goes as planned, you will see an SMTP dialog like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
=== Trying localhost:25...
|
||||||
|
=== Connected to localhost.
|
||||||
|
<- 220 mail ESMTP Postfix (Debian)
|
||||||
|
-> EHLO mail
|
||||||
|
<- 250-mail
|
||||||
|
<- 250-PIPELINING
|
||||||
|
<- 250-SIZE 10240000
|
||||||
|
<- 250-VRFY
|
||||||
|
<- 250-ETRN
|
||||||
|
<- 250-STARTTLS
|
||||||
|
<- 250-ENHANCEDSTATUSCODES
|
||||||
|
<- 250-8BITMIME
|
||||||
|
<- 250-DSN
|
||||||
|
<- 250-SMTPUTF8
|
||||||
|
<- 250 CHUNKING
|
||||||
|
-> MAIL FROM:<root@mail>
|
||||||
|
<- 250 2.1.0 Ok
|
||||||
|
-> RCPT TO:<john@example.org>
|
||||||
|
<- 250 2.1.5 Ok
|
||||||
|
-> DATA
|
||||||
|
<- 354 End data with <CR><LF>.<CR><LF>
|
||||||
|
-> Date: Sun, 24 Aug 2025 21:08:59 +0000
|
||||||
|
-> To: john@example.org
|
||||||
|
-> From: root@mail
|
||||||
|
-> Subject: test Sun, 24 Aug 2025 21:08:59 +0000
|
||||||
|
-> Message-Id: <20250824210859.021444@mail>
|
||||||
|
-> X-Mailer: swaks v20240103.0 jetmore.org/john/code/swaks/
|
||||||
|
->
|
||||||
|
-> This is a test mailing
|
||||||
|
->
|
||||||
|
->
|
||||||
|
-> .
|
||||||
|
<- 250 2.0.0 Ok: queued as 2742B221FA
|
||||||
|
-> QUIT
|
||||||
|
<- 221 2.0.0 Bye
|
||||||
|
=== Connection closed with remote host.
|
||||||
|
```
|
||||||
|
|
||||||
|
If you see a `250 2.0.0 Ok: queued as…" near the end of this dialog, then Postfix has received the email successfully.
|
||||||
|
|
||||||
|
Check if Postfix managed to pass the email to Dovecot:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
journalctl -n 10 -u dovecot
|
||||||
|
```
|
||||||
|
|
||||||
|
The line you are looking for looks like:
|
||||||
|
|
||||||
|
```
|
||||||
|
Aug 24 21:36:22 mail dovecot[23214]: lmtp(john@example.org)<…><…>: msgid=<20250824213622.023221@mail>: saved mail to INBOX
|
||||||
|
```
|
||||||
|
|
||||||
|
Does it say `saved mail to INBOX`? Awesome. The email should be visible in John's home directory. Check it:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
find /var/vmail/example.org/john
|
||||||
|
```
|
||||||
|
|
||||||
|
Does it look like this?
|
||||||
|
|
||||||
|
```
|
||||||
|
/var/vmail/
|
||||||
|
/var/vmail/example.org
|
||||||
|
/var/vmail/example.org/john
|
||||||
|
/var/vmail/example.org/john/Maildir
|
||||||
|
/var/vmail/example.org/john/Maildir/maildirfolder
|
||||||
|
/var/vmail/example.org/john/Maildir/new
|
||||||
|
/var/vmail/example.org/john/Maildir/new/1756071382.M198387P23222.mail,S=635,W=655
|
||||||
|
/var/vmail/example.org/john/Maildir/cur
|
||||||
|
/var/vmail/example.org/john/Maildir/tmp
|
||||||
|
/var/vmail/example.org/john/Maildir/dovecot-uidvalidity.68ab85d6
|
||||||
|
/var/vmail/example.org/john/Maildir/dovecot.index.log
|
||||||
|
/var/vmail/example.org/john/Maildir/dovecot-uidvalidity
|
||||||
|
/var/vmail/example.org/john/Maildir/dovecot.index.cache
|
||||||
|
/var/vmail/example.org/john/Maildir/dovecot-uidlist
|
||||||
|
/var/vmail/example.org/john/Maildir/dovecot.list.index.log
|
||||||
|
```
|
||||||
|
|
||||||
|
The important file here is `…/Maildir/new/1756071382.M198387P23222.mail,S=635,W=655`. The numbers will look differently
|
||||||
|
on your system. But this is the actual mail that got delivered. You can view it with `cat` and will find the test email
|
||||||
|
you just sent using `swaks`.
|
||||||
|
|
||||||
|
Don't worry about the other files like `maildirfolder` or the files that sound like `dovecot…`. Those help Dovecot keep
|
||||||
|
track of the mailbox. You can safely ignore them.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue