Mailinglisten mit Nextcloud und Exim

Wer eine Owncloud/Nextcloud mit vielen Nutzern, zum Beispiel für einen Verein, administriert hat potientiell auch Mailinglisten für die Mitglieder bzw. Sammeladressen z.B. für den Vorstand, auf einem Exim-Server in Betrieb. An beiden Stellen müssen Gruppen definiert und Emailadressen gepflegt werden. Mit dem hier vorgestellten Perl-Skript, lässt sich der Verwaltungsaufwand reduzieren, da alle Daten nur noch in der Owncloud gepflegt werden müssen.

Jede in Owncloud definierte Gruppe entspricht dabei einer Mailingliste bzw. Sammeladresse. Um beim Beispiel eines Vereins zu bleiben: Alle Vereinsmitglieder sind Teil der Owncloud-Gruppe mitglieder, alle Vorstandsmitglieder sind Teil der Gruppe vorstand. Daraus soll eine Mailingliste mitglieder@domain.com und eine Sammeladresse vorstand@domain.com entstehen. Der einzige Unterschied zwischen Mailingliste und Sammeladresse ist hierbei: auf die Mailingliste sollen nur Mitglieder der Gruppe schreiben dürfen, an die Sammeladresse soll sich jeder wenden können. Das Perl-Skript generate-mailinglists.pl realisiert genau das. Es erzeugt (in diesem Beispiel) folgende Datei, welche vom Mailserver Exim interpretiert wird:

[~/.forward]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Exim filter <<-- Do not edit or remove this line
#

if
$original_local_part is "vorstand"
then
if $header_from does not contain "vorstand1@gmx.net" then deliver vorstand1@gmx.net endif
if $header_from does not contain "vorstand2@web.de" then deliver vorstand2@web.de endif
endif

if
$original_local_part is "mitglieder"
then if
(
$header_from does contain "mitglied1@gmx.net" or
$header_from does contain "mitglied2@web.de" or
$header_from does contain "vorstand1@gmx.de" or
$header_from does contain "vorstand2@web.de"
...
)
then
if $header_from does not contain "mitglied1@gmx.net" then deliver mitglied1@gmx.net endif
if $header_from does not contain "mitglied2@web.de" then deliver mitglied2@web.de endif
if $header_from does not contain "vorstand1@gmx.net" then deliver vorstand1@gmx.net endif
if $header_from does not contain "vorstand2@web.de" then deliver vorstand2@web.de endif
...
else
seen mail to $sender_address from "noreply@domain.com" subject "Re: $header_subject" text "Die Email konnte nicht zugestellt werden, da Ihre Emailadresse für diesen Verteiler nicht freigeschaltet ist."
endif
endif

Optional kann eine Catch-All Emailadresse definiert werden, an die alle verbleibenden Emails gesendet werden.

Das Skript, sowie eine Readme-Datei mit Informationen zur genauen Verwendung ist auf github verfügbar: https://github.com/jowi24/ocmailinglists

Es ist außerdem sinnvoll, über einen Exim-Filter bestimmte Header der eingehenden Mails vor Weiterleitung wie folgt zu bearbeiten:

[/etc/mail/exim.conf]
1
2
3
4
...
system_filter = /etc/mail/system.filter
system_filter_user = exim
...
[/etc/mail/system.filter]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#
# Exim system filter
#

# modify mails going to mailing list domains
if first_delivery and $recipients contains "@domain.com"
then

# add list name to subject, if only the list is in the to header (avoids adding this to replies)
headers add "Old-Subject: $h_subject"
if ${local_part:$recipients} is not ""
then
headers remove "Subject"
headers add "Subject: [${local_part:$recipients}] $h_old-subject"
headers remove "Old-Subject"
endif

# remove DKIM as we modify the header from
headers remove "DKIM-Signature"

# set reply to header, only if it was not set before
headers add "X-Reply-Address: $reply_address"
headers remove "Reply-To"
headers add "Reply-To: $h_x-reply-address"
headers remove "X-Reply-Address"

# set from header to a the local domains
headers add "X-Original-From: $h_from"
headers remove "From"
headers add "From: \"${sg{$header_x-original-from:}{\"}{}}\" <noreply@domain.com>"

# mark this mail as list mail
headers add "Precedence: list"
endif

Update 2016-10-26

Ursprünglich wurde das Feld $header_to ausgewertet, was natürlich nicht hinreichend ist, da die Mailingliste auch im CC stehen könnte (z.B. bei einem Reply-To-All) oder auch nur in BCC. Es sollte daher auf die Exim-Variable $original_local_part zurückgegriffen werden. Artikel und Skript wurden entsprechend angepasst.

Ebenso empfiehlt es sich, bestimmte Header in der empfangenen Mail zu bearbeiten. Da Header durch ein User-Forward-File nicht verändert werden dürfen, lohnt sich hier der Einsatz eines Exim System-Filters. Auch dies wurde in obigem Artikel ergänzt.