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 "@splidejs/splide/css";
|
||||
import { Splide, SplideSlide } from "astro-splide";
|
||||
|
||||
import { Steps } from "@astrojs/starlight/components";
|
||||
|
||||
import Box from "../../../components/Box.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} />
|
||||
|
||||
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
|
||||
slug: ispmail-trixie/receive-emails-postfix
|
||||
slug: ispmail-trixie/postfix
|
||||
sidebar:
|
||||
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:
|
||||
|
||||
```sh
|
||||
cat > /etc/postfix/virtual-mailbox-domains.cf << EOF
|
||||
cat > /etc/postfix/mariadb-virtual-mailbox-domains.cf << EOF
|
||||
user = mailserver
|
||||
password = SECOND-PASSWORD-HERE
|
||||
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:
|
||||
|
||||
```sh
|
||||
cat > /etc/postfix/virtual-alias-maps.cf << EOF
|
||||
cat > /etc/postfix/mariadb-virtual-alias-maps.cf << EOF
|
||||
user = mailserver
|
||||
password = SECOND-PASSWORD-HERE
|
||||
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:
|
||||
|
||||
```sh
|
||||
cat > /etc/postfix/virtual-mailbox-maps.cf << EOF
|
||||
cat > /etc/postfix/mariadb-virtual-mailbox-maps.cf << EOF
|
||||
user = mailserver
|
||||
password = SECOND-PASSWORD-HERE
|
||||
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:
|
||||
|
||||
```sh
|
||||
postconf virtual_mailbox_domains=mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
|
||||
postconf virtual_mailbox_maps=mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
|
||||
postconf virtual_alias_maps=mysql:/etc/postfix/mysql-virtual-alias-maps.cf
|
||||
postconf virtual_mailbox_domains=mysql:/etc/postfix/mariadb-virtual-mailbox-domains.cf
|
||||
postconf virtual_mailbox_maps=mysql:/etc/postfix/mariadb-virtual-mailbox-maps.cf
|
||||
postconf virtual_alias_maps=mysql:/etc/postfix/mariadb-virtual-alias-maps.cf
|
||||
|
||||
chown root:postfix /etc/postfix/*.cf
|
||||
chmod o= /etc/postfix/*.cf
|
||||
chown root:postfix /etc/postfix/mariadb-*.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
|
||||
|
|
@ -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_):
|
||||
|
||||
```sh
|
||||
postmap -q example.org mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
|
||||
postmap -q jack@example.org mysql:/etc/postfix/mysql-virtual-alias-maps.cf
|
||||
postmap -q john@example.org mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
|
||||
postmap -q example.org mysql:/etc/postfix/mariadb-virtual-mailbox-domains.cf
|
||||
postmap -q jack@example.org mysql:/etc/postfix/mariadb-virtual-alias-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:
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: "Deliver emails: Dovecot"
|
||||
lastUpdated: 2025-08-22
|
||||
slug: ispmail-trixie/deliver-emails-dovecot
|
||||
title: "Dovecot"
|
||||
lastUpdated: 2025-08-24
|
||||
slug: ispmail-trixie/dovecot
|
||||
sidebar:
|
||||
order: 165
|
||||
---
|
||||
|
|
@ -9,19 +9,7 @@ sidebar:
|
|||
import { Aside } from "@astrojs/starlight/components";
|
||||
import StepListReceive from "../../../components/StepListReceive.astro";
|
||||
|
||||
## About LMTP
|
||||
|
||||
<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.
|
||||
<StepListReceive currentStep={4} />
|
||||
|
||||
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_home = /var/vmail/%{user | domain}/%{user | username}
|
||||
mail_path = ~/Maildir
|
||||
mail_uid = vmail
|
||||
mail_gid = vmail
|
||||
```
|
||||
|
||||
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
|
||||
is that we will store other data in the user's _home_ directory as well that should not conflict with the mailbox
|
||||
directory.
|
||||
- **mail_uid**/**mail_gid**/: All mailboxes are stored on disk under the owner _vmail_.
|
||||
|
||||
### 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.
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -142,7 +145,7 @@ userdb 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
|
||||
uid
|
||||
gid
|
||||
uid vmail
|
||||
gid vmail
|
||||
home /var/vmail/example.org/john
|
||||
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