Skip to content

Character Encoding Issues in some Emails #6935

@smlftz

Description

@smlftz

Contribution guidelines

Checklist prior issue creation

  • I understand that failure to follow below instructions may cause this issue to be closed.
  • I understand that vague, incomplete or inaccurate information may cause this issue to be closed.
  • I understand that this form is intended solely for reporting software bugs and not for support-related inquiries.
  • I understand that all responses are voluntary and community-driven, and do not constitute commercial support.
  • I confirm that I have reviewed previous issues to ensure this matter has not already been addressed.
  • I confirm that my environment meets all prerequisite requirements as specified in the official documentation.

Description

Certain emails generated by the system contain character encoding errors. These errors result in unreadable or corrupted characters appearing in the message body.
This only seems to happen with plain text emails.

Example below:
The mail I wrote:

Image

How the email appeared to the recipient:

Image

The issue appears to be related to the server-side generated signatures in combination with umlauts.

Steps to reproduce:

  1. Write a plain text email
  2. Compare the email that was send with the email recieved
  3. Sometimes those encoding problems appear

Logs:

---

Which branch are you using?

master (stable)

Which architecture are you using?

x86_64

Operating System:

Debian GNU/Linux 12 (bookworm)

Server/VM specifications:

80GiB RAM

Is Apparmor, SELinux or similar active?

Apparmor active in VM

Virtualization technology:

Proxmox VM (no LXC)

Docker version:

Version: 28.4.0

docker-compose version or docker compose version:

v2.39.2

mailcow version:

2025-10

Reverse proxy:

HA Proxy

Logs of git diff:

[certificates]

@@ -2,7 +2,8 @@
 # global_sieve_before -> user sieve_before (mailcow UI) -> user sieve_after (mailcow UI) -> global_sieve_after
 
 require ["mailbox", "fileinto"];
-
+require ["editheader"];
+require ["variables"];
 if header :contains ["Chat-Version"] [""] {
   if mailboxexists "DeltaChat" {
     fileinto "DeltaChat";
@@ -11,3 +12,26 @@ if header :contains ["Chat-Version"] [""] {
   }
   stop;
 }
+
+# add an external domain header to all email not coming from our own domains
+if allof(
+  not address :domain :is ["from"] ["karcoma.com","karcoma.net","karcoma.de","karcoma.ch","karcoma.cloud","srvesxi1.karcoma.net","srvesxi2.karcoma.net"],
+  not header :contains "Subject" ["[EXTERN]"]
+)
+{
+  addheader "X-External-Domain" "This Message originated outside of mind.";
+  # Match the entire subject ...
+  if header :matches "Subject" "*" {
+     # ... to get it in a match group that can then be stored in a variable:
+     set "subject" "${1}";
+  }
+
+  # We can't "replace" a header, but we can delete (all instances of) it and
+  # re-add (a single instance of) it:
+  deleteheader "Subject";
+  # Append/prepend as you see fit
+  addheader :last "Subject" "[EXTERN] ${subject}";
+  # Note that the header is added ":last" (so it won't appear before possible
+  # "Received" headers).
+
+}
\ No newline at end of file
diff --git a/data/conf/postfix/main.cf b/data/conf/postfix/main.cf
index f091cb3f..3db68340 100644
--- a/data/conf/postfix/main.cf
+++ b/data/conf/postfix/main.cf
@@ -174,3 +174,30 @@ lmtp_destination_recipient_limit=1
 
 # DO NOT EDIT ANYTHING BELOW #
 # Overrides #
+
+postscreen_dnsbl_sites = wl.mailspike.net=127.0.0.[18;19;20]*-2
+  hostkarma.junkemailfilter.com=127.0.0.1*-2
+  list.dnswl.org=127.0.[0..255].0*-2
+  list.dnswl.org=127.0.[0..255].1*-4
+  list.dnswl.org=127.0.[0..255].2*-6
+  list.dnswl.org=127.0.[0..255].3*-8
+  bl.spamcop.net*2
+  bl.suomispam.net*2
+  hostkarma.junkemailfilter.com=127.0.0.2*3
+  hostkarma.junkemailfilter.com=127.0.0.4*2
+  hostkarma.junkemailfilter.com=127.0.1.2*1
+  backscatter.spameatingmonkey.net*2
+  bl.ipv6.spameatingmonkey.net*2
+  bl.spameatingmonkey.net*2
+  b.barracudacentral.org=127.0.0.2*7
+  bl.mailspike.net=127.0.0.2*5
+  bl.mailspike.net=127.0.0.[10;11;12]*4
+  zen.spamhaus.org=127.0.0.[10;11]*8
+  zen.spamhaus.org=127.0.0.[4..7]*6
+  zen.spamhaus.org=127.0.0.3*4
+  zen.spamhaus.org=127.0.0.2*3
+
+# User Overrides
+myhostname = mail.karcoma.net
+smtp_address_preference = ipv4
+inet_protocols = ipv4
diff --git a/data/conf/unbound/unbound.conf b/data/conf/unbound/unbound.conf
index 27110c04..354412fd 100644
--- a/data/conf/unbound/unbound.conf
+++ b/data/conf/unbound/unbound.conf
@@ -4,7 +4,7 @@ server:
   interface: ::0
   logfile: /dev/console
   do-ip4: yes
-  do-ip6: yes
+  do-ip6: no
   do-udp: yes
   do-tcp: yes
   do-daemonize: no
@@ -33,7 +33,7 @@ server:
   max-udp-size: 4096
   msg-buffer-size: 65552
   unwanted-reply-threshold: 10000
-  ipsecmod-enabled: no
+  ipsecmod-enabled: nos
 
 remote-control:
   control-enable: yes
@@ -43,3 +43,7 @@ remote-control:
   server-cert-file: "/etc/unbound/unbound_server.pem"
   control-key-file: "/etc/unbound/unbound_control.key"
   control-cert-file: "/etc/unbound/unbound_control.pem"
+
+forward-zone:
+  name: "."
+  forward-addr: 10.11.0.1
diff --git a/docker-compose.yml b/docker-compose.yml
index 86a4f401..2b6996c0 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -666,7 +666,7 @@ networks:
       driver: default
       config:
         - subnet: ${IPV4_NETWORK:-172.22.1}.0/24
-        - subnet: ${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
+       # - subnet: ${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
 
 volumes:
   vmail-vol-1:

Logs of iptables -L -vn:

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  23M   23G MAILCOW    0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* mailcow */
  23M   23G DOCKER-USER  0    --  *      *       0.0.0.0/0            0.0.0.0/0           
  23M   23G DOCKER-FORWARD  0    --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (3 references)
 pkts bytes target     prot opt in     out     source               destination         
52147 3122K ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.10          tcp dpt:443
   26  1432 ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.10          tcp dpt:80
 1412 79820 ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.253         tcp dpt:587
 2156  122K ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.253         tcp dpt:465
 2056  123K ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.253         tcp dpt:25
    0     0 ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.249         tcp dpt:6379
    0     0 ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.250         tcp dpt:12345
  194 10936 ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.250         tcp dpt:4190
16026  958K ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.250         tcp dpt:995
19012 1135K ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.250         tcp dpt:993
 2589  161K ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.250         tcp dpt:143
 1966  113K ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.250         tcp dpt:110
    0     0 ACCEPT     6    --  !br-mailcow br-mailcow  0.0.0.0/0            172.22.1.7           tcp dpt:3306
    0     0 DROP       0    --  !br-mailcow br-mailcow  0.0.0.0/0            0.0.0.0/0           
    0     0 DROP       0    --  !br-7d308ea01d95 br-7d308ea01d95  0.0.0.0/0            0.0.0.0/0           
    0     0 DROP       0    --  !docker0 docker0  0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-BRIDGE (1 references)
 pkts bytes target     prot opt in     out     source               destination         
97584 5827K DOCKER     0    --  *      br-mailcow  0.0.0.0/0            0.0.0.0/0           
    0     0 DOCKER     0    --  *      br-7d308ea01d95  0.0.0.0/0            0.0.0.0/0           
    0     0 DOCKER     0    --  *      docker0  0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-CT (1 references)
 pkts bytes target     prot opt in     out     source               destination         
9835K 4554M ACCEPT     0    --  *      br-mailcow  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     0    --  *      br-7d308ea01d95  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     0    --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED

Chain DOCKER-FORWARD (1 references)
 pkts bytes target     prot opt in     out     source               destination         
  23M   23G DOCKER-CT  0    --  *      *       0.0.0.0/0            0.0.0.0/0           
  13M   18G DOCKER-INTERNAL  0    --  *      *       0.0.0.0/0            0.0.0.0/0           
  13M   18G DOCKER-BRIDGE  0    --  *      *       0.0.0.0/0            0.0.0.0/0           
  13M   18G ACCEPT     0    --  br-mailcow *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     0    --  br-7d308ea01d95 *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     0    --  docker0 *       0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-INTERNAL (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain MAILCOW (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       6    --  !br-mailcow br-mailcow  0.0.0.0/0            0.0.0.0/0            /* mailcow isolation */

Logs of ip6tables -L -vn:

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MAILCOW    0    --  *      *       ::/0                 ::/0                 /* mailcow */
    0     0 DOCKER-USER  0    --  *      *       ::/0                 ::/0                
    0     0 DOCKER-FORWARD  0    --  *      *       ::/0                 ::/0                

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (0 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-BRIDGE (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-CT (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-FORWARD (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DOCKER-CT  0    --  *      *       ::/0                 ::/0                
    0     0 DOCKER-INTERNAL  0    --  *      *       ::/0                 ::/0                
    0     0 DOCKER-BRIDGE  0    --  *      *       ::/0                 ::/0                

Chain DOCKER-INTERNAL (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain MAILCOW (1 references)
 pkts bytes target     prot opt in     out     source               destination

Logs of iptables -L -vn -t nat:

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MAILCOW    0    --  *      *       ::/0                 ::/0                 /* mailcow */
    0     0 DOCKER-USER  0    --  *      *       ::/0                 ::/0                
    0     0 DOCKER-FORWARD  0    --  *      *       ::/0                 ::/0                

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (0 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-BRIDGE (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-CT (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-FORWARD (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DOCKER-CT  0    --  *      *       ::/0                 ::/0                
    0     0 DOCKER-INTERNAL  0    --  *      *       ::/0                 ::/0                
    0     0 DOCKER-BRIDGE  0    --  *      *       ::/0                 ::/0                

Chain DOCKER-INTERNAL (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination         

Chain MAILCOW (1 references)
 pkts bytes target     prot opt in     out     source               destination         
root@SRVPRL20:/opt/mailcow-dockerized# iptables -L -vn -t nat
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
97600 5828K DOCKER     0    --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DOCKER     0    --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MASQUERADE  0    --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
    0     0 MASQUERADE  0    --  *      !br-7d308ea01d95  172.18.0.0/16        0.0.0.0/0           
1727K  134M MASQUERADE  0    --  *      !br-mailcow  172.22.1.0/24        0.0.0.0/0           

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DNAT       6    --  !br-mailcow *       0.0.0.0/0            127.0.0.1            tcp dpt:13306 to:172.22.1.7:3306
 1966  113K DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:110 to:172.22.1.250:110
 2589  161K DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:143 to:172.22.1.250:143
19011 1135K DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:993 to:172.22.1.250:993
16026  958K DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:995 to:172.22.1.250:995
  194 10936 DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:4190 to:172.22.1.250:4190
    0     0 DNAT       6    --  !br-mailcow *       0.0.0.0/0            127.0.0.1            tcp dpt:19991 to:172.22.1.250:12345
    0     0 DNAT       6    --  !br-mailcow *       0.0.0.0/0            127.0.0.1            tcp dpt:7654 to:172.22.1.249:6379
 2056  123K DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:25 to:172.22.1.253:25
 2156  122K DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:465 to:172.22.1.253:465
 1412 79820 DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:587 to:172.22.1.253:587
   26  1432 DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.22.1.10:80
52151 3123K DNAT       6    --  !br-mailcow *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443 to:172.22.1.10:443

Logs of ip6tables -L -vn -t nat:

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DOCKER     0    --  *      *       ::/0                 ::/0                 ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DOCKER     0    --  *      *       ::/0                !::1                  ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination

DNS check:

198.252.206.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions