✉️ Composable all-in-one mail server.

Overview

Maddy Mail Server

Composable all-in-one mail server.

Maddy Mail Server implements all functionality required to run a e-mail server. It can send messages via SMTP (works as MTA), accept messages via SMTP (works as MX) and store messages while providing access to them via IMAP. In addition to that it implements auxiliary protocols that are mandatory to keep email reasonably secure (DKIM, SPF, DMARC, DANE, MTA-STS).

It replaces Postfix, Dovecot, OpenDKIM, OpenSPF, OpenDMARC and more with one daemon with uniform configuration and minimal maintenance cost.

Note: IMAP storage is "beta". If you are looking for stable and feature-packed implementation you may want to use Dovecot instead. maddy still can handle message delivery business.

builds.sr.ht status Issues tracker

Comments
  • Code license change

    Code license change

    I have some thoughts regarding changing maddy's source code license. Frankly, I never thought I would make it that far and MIT license was always my "don't care" choice for small projects and it was the license picked by @emersion, likely for the same reason. It is hard to call maddy a small project now, right? In other words, I now want at least my future work to remain in open-source due to the amount of effort I am putting into it. Therefore, I am considering changing current license (MIT) to GPLv3.

    • Currently existing releases will remain MIT-licensed as there is no legal path for me to revoke it neither I want to bother rewriting history. maddy ~~0.3.3~~, 0.4 and all future releases will be distributed under terms of the GPLv3 license.
    • Supplementary libraries I wrote for use in maddy (including go-imap-sql backend and go-imap-backend-tests suite) will continue using MIT license. I will still try to extract parts of maddy code base into such MIT-licensed libraries for wider use (still hoping to get around to upstream DMARC check code to go-msgauth).
    • I am not intending to act hostile towards business that may want benefit from maddy project in the future. That is the reason I am not selecting AGPL license - if you modify maddy for your own needs and provide email service, I am completely fine with that.
    • I am concerned about how that might affect upcoming work to create public API for third-party modules. Changing license to GPLv3 will require such extensions to be also GPLv3 since they will need to use some of maddy's code.
    • ~~I believe I do not need to ask each of 13 contributors to agree on license change since MIT license itself allows "anyone" (including me, that is) to "sublicense" software.~~

    I would like to hear any opinions regarding my plans from that small community I managed to build so far. CC @emersion @Hexawolf

    ready-for-release 
    opened by foxcpp 23
  • Modular design

    Modular design

    https://github.com/emersion/maddy/issues/15#issuecomment-471542210

    -- Original post:

    Let's say I configured IMAP endpoint as follows (where first line creates IMAP backend):

    imap://127.0.0.1:1993 {
        sql sqlite3 maddy.db
    }
    

    Then I want to have SMTP endpoint that will deliver mail to same storage. How would I do this?

    1. Assuming that backend also provides implementation of SMTP upstream (perhaps as separate object).
    smtp://127.0.0.1:1025 {
    	sql sqlite3 maddy.db
    }
    

    This approach creates another set of problems, because it now requires two separate backend/upstream objects to coordinate access to the same storage (think of IMAP unilateral updates). Global variables? External IPC sockets? All this seems to be dirty solution.

    What is we can create one "storage" object and associate it with multiple IMAP/SMTP endpoints? This will transform "another set of problems" into just serialization of access to storage object. Which is easily solved by throwing some mutexes into it (or even without them, I haven't tested that but go-sqlmail backend object should be safe for concurrent use by multiple goroutines).

    It also reduces resources usage (we will have only one SQLite "connection" page cache, for example)

    Now I can imagine something like this:

    backend sql arbitrary_name {
      driver sqlite3
      dsn maddy.db
    }
    
    imap://127.0.0.1:1993 {
      backend arbitrary_name 
      # of course this requires storage object to implement go-imap's Backend interface
    }
    
    smtp://127.0.0.1:1025 {
      backend arbitrary_name 
      # and also go-smtp's Backend here now.
    }
    

    What do you think?

    opened by foxcpp 19
  • 1:N address expansion

    1:N address expansion

    Use case

    It it described on wikipedia:

    • Role-addresses info, sales, postmaster, and similar names[6] can appear to the left of @ in email addresses. An organization may forward messages intended for a given role to the address of the person(s) currently functioning in that role or office.

    • Multiple, or discontinued addresses When users change their email address, or have several addresses, the user or an administrator may set up forwarding from these addresses, if still valid, to a single current one, in order to avoid losing messages.

    Your idea for a solution

    I haven't looked at the source code of maddy. It would be nice to store forward rules in a table such as

    (1, "[email protected]", "[email protected]")
    (2, "[email protected]", "[email protected]")
    (3, "[email protected]", "[email protected]")
    

    and so when a mail is received the To header would be checked against "[email protected]" and automatically forwarded to "[email protected]", "[email protected]" and "[email protected]". The table could be altered (and reloaded?) via the command line or other mechanisms.

    I'm not sure how difficult would that be.

    • [ ] I'm willing to help with the implementation
    new feature ready-for-release 
    opened by greengekota 18
  • Frequent OOM issues when importing a mailbox

    Frequent OOM issues when importing a mailbox

    Describe the bug

    I am copying the Sent mailbox, via mac Mail, from my gmail (downloaded over imap) and am getting frequent OOM crashes.

    Steps to reproduce

    Not really sure. I can't really tell if it is particular messages that are causing the issue or the quantity of them.

    Log files

    Mac Mail error:

    The IMAP command “APPEND” (to Sent) failed with server error: CreateMessage (extractCachedData): unexpected EOF.
    
    syslog
    Aug 26 22:28:31 localhost kernel: [10811.574833] systemd-udevd invoked oom-killer: gfp_mask=0x100cca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=-1000
    Aug 26 22:28:31 localhost kernel: [10811.574839] CPU: 0 PID: 389 Comm: systemd-udevd Not tainted 5.4.0-80-generic #90-Ubuntu
    Aug 26 22:28:31 localhost kernel: [10811.574839] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014
    Aug 26 22:28:31 localhost kernel: [10811.574840] Call Trace:
    Aug 26 22:28:31 localhost kernel: [10811.574852]  dump_stack+0x6d/0x8b
    Aug 26 22:28:31 localhost kernel: [10811.574856]  dump_header+0x4f/0x1eb
    Aug 26 22:28:31 localhost kernel: [10811.574858]  oom_kill_process.cold+0xb/0x10
    Aug 26 22:28:31 localhost kernel: [10811.574862]  out_of_memory.part.0+0x1df/0x3d0
    Aug 26 22:28:31 localhost kernel: [10811.574863]  out_of_memory+0x6d/0xd0
    Aug 26 22:28:31 localhost kernel: [10811.574866]  __alloc_pages_slowpath+0xd5e/0xe50
    Aug 26 22:28:31 localhost kernel: [10811.574868]  __alloc_pages_nodemask+0x2d0/0x320
    Aug 26 22:28:31 localhost kernel: [10811.574870]  alloc_pages_current+0x87/0xe0
    Aug 26 22:28:31 localhost kernel: [10811.574873]  __page_cache_alloc+0x72/0x90
    Aug 26 22:28:31 localhost kernel: [10811.574874]  pagecache_get_page+0xbf/0x300
    Aug 26 22:28:31 localhost kernel: [10811.574876]  filemap_fault+0x6b2/0xa50
    Aug 26 22:28:31 localhost kernel: [10811.574878]  ? mem_cgroup_charge_statistics+0x51/0xe0
    Aug 26 22:28:31 localhost kernel: [10811.574879]  ? filemap_map_pages+0x24c/0x380
    Aug 26 22:28:31 localhost kernel: [10811.574884]  ext4_filemap_fault+0x32/0x50
    Aug 26 22:28:31 localhost kernel: [10811.574885]  __do_fault+0x3c/0x130
    Aug 26 22:28:31 localhost kernel: [10811.574887]  do_fault+0x24b/0x640
    Aug 26 22:28:31 localhost kernel: [10811.574888]  __handle_mm_fault+0x4c5/0x7a0
    Aug 26 22:28:31 localhost kernel: [10811.574889]  handle_mm_fault+0xca/0x200
    Aug 26 22:28:31 localhost kernel: [10811.574893]  do_user_addr_fault+0x1f9/0x450
    Aug 26 22:28:31 localhost kernel: [10811.574894]  __do_page_fault+0x58/0x90
    Aug 26 22:28:31 localhost kernel: [10811.574895]  do_page_fault+0x2c/0xe0
    Aug 26 22:28:31 localhost kernel: [10811.574897]  do_async_page_fault+0x39/0x70
    Aug 26 22:28:31 localhost kernel: [10811.574899]  async_page_fault+0x34/0x40
    Aug 26 22:28:31 localhost kernel: [10811.574902] RIP: 0033:0x558eb2d6c970
    Aug 26 22:28:31 localhost kernel: [10811.574909] Code: Bad RIP value.
    Aug 26 22:28:31 localhost kernel: [10811.574910] RSP: 002b:00007ffd13be9b78 EFLAGS: 00010206
    Aug 26 22:28:31 localhost kernel: [10811.574911] RAX: 0000000000000000 RBX: 0000558eb4bdcd28 RCX: 00000000000037a6
    Aug 26 22:28:31 localhost kernel: [10811.574912] RDX: 0000558eb4bdcd28 RSI: 0000000000000000 RDI: 0000558eb4bdadd0
    Aug 26 22:28:31 localhost kernel: [10811.574912] RBP: 0000558eb4bdadd0 R08: 00007ffd13bfb0f0 R09: 00007ffd13be9ba8
    Aug 26 22:28:31 localhost kernel: [10811.574913] R10: 00007ffd13be9ba0 R11: 0000000000002a3b R12: 0000000000000001
    Aug 26 22:28:31 localhost kernel: [10811.574913] R13: 0000558eb4bdccf0 R14: 00007ffd13be9c00 R15: 0000000000000000
    Aug 26 22:28:31 localhost kernel: [10811.574914] Mem-Info:
    Aug 26 22:28:31 localhost kernel: [10811.574917] active_anon:109142 inactive_anon:109595 isolated_anon:0
    Aug 26 22:28:31 localhost kernel: [10811.574917]  active_file:7 inactive_file:9 isolated_file:0
    Aug 26 22:28:31 localhost kernel: [10811.574917]  unevictable:0 dirty:4 writeback:0 unstable:0
    Aug 26 22:28:31 localhost kernel: [10811.574917]  slab_reclaimable:4988 slab_unreclaimable:8554
    Aug 26 22:28:31 localhost kernel: [10811.574917]  mapped:404 shmem:422 pagetables:1197 bounce:0
    Aug 26 22:28:31 localhost kernel: [10811.574917]  free:12110 free_pcp:263 free_cma:0
    Aug 26 22:28:31 localhost kernel: [10811.574919] Node 0 active_anon:436568kB inactive_anon:438380kB active_file:28kB inactive_file:36kB unevictable:0kB isolated(anon):0kB isolated(file):0kB mapped:1616kB dirty:16kB writeback:0kB shmem:1688kB shmem_thp: 0kB shmem_pmdmapped: 0kB anon_thp: 133120kB writeback_tmp:0kB unstable:0kB all_unreclaimable? no
    Aug 26 22:28:31 localhost kernel: [10811.574920] Node 0 DMA free:4284kB min:780kB low:972kB high:1164kB active_anon:7436kB inactive_anon:3964kB active_file:0kB inactive_file:0kB unevictable:0kB writepending:0kB present:15992kB managed:15908kB mlocked:0kB kernel_stack:0kB pagetables:16kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB
    Aug 26 22:28:31 localhost kernel: [10811.574922] lowmem_reserve[]: 0 877 877 877 877
    Aug 26 22:28:31 localhost kernel: [10811.574923] Node 0 DMA32 free:44156kB min:44272kB low:55340kB high:66408kB active_anon:429132kB inactive_anon:434416kB active_file:28kB inactive_file:36kB unevictable:0kB writepending:16kB present:1032048kB managed:988820kB mlocked:0kB kernel_stack:1836kB pagetables:4772kB bounce:0kB free_pcp:1052kB local_pcp:1052kB free_cma:0kB
    Aug 26 22:28:31 localhost kernel: [10811.574926] lowmem_reserve[]: 0 0 0 0 0
    Aug 26 22:28:31 localhost kernel: [10811.574927] Node 0 DMA: 5*4kB (UE) 5*8kB (UME) 2*16kB (ME) 3*32kB (UME) 2*64kB (UM) 1*128kB (E) 3*256kB (UME) 2*512kB (ME) 2*1024kB (UE) 0*2048kB 0*4096kB = 4284kB
    Aug 26 22:28:31 localhost kernel: [10811.574931] Node 0 DMA32: 385*4kB (UEH) 407*8kB (UEH) 284*16kB (UEH) 182*32kB (UMEH) 125*64kB (UME) 62*128kB (UE) 25*256kB (UME) 3*512kB (ME) 5*1024kB (M) 0*2048kB 0*4096kB = 44156kB
    Aug 26 22:28:31 localhost kernel: [10811.574937] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB
    Aug 26 22:28:31 localhost kernel: [10811.574938] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
    Aug 26 22:28:31 localhost kernel: [10811.574938] 56606 total pagecache pages
    Aug 26 22:28:31 localhost kernel: [10811.574939] 56162 pages in swap cache
    Aug 26 22:28:31 localhost kernel: [10811.574940] Swap cache stats: add 364954189, delete 364898027, find 157661067/199756130
    Aug 26 22:28:31 localhost kernel: [10811.574940] Free swap  = 0kB
    Aug 26 22:28:31 localhost kernel: [10811.574940] Total swap = 524284kB
    Aug 26 22:28:31 localhost kernel: [10811.574941] 262010 pages RAM
    Aug 26 22:28:31 localhost kernel: [10811.574941] 0 pages HighMem/MovableOnly
    Aug 26 22:28:31 localhost kernel: [10811.574941] 10828 pages reserved
    Aug 26 22:28:31 localhost kernel: [10811.574942] 0 pages cma reserved
    Aug 26 22:28:31 localhost kernel: [10811.574942] 0 pages hwpoisoned
    Aug 26 22:28:31 localhost kernel: [10811.574942] Tasks state (memory values in pages):
    Aug 26 22:28:31 localhost kernel: [10811.574942] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
    Aug 26 22:28:31 localhost kernel: [10811.574946] [    341]     0   341    12852       18   135168      267          -250 systemd-journal
    Aug 26 22:28:31 localhost kernel: [10811.574947] [    389]     0   389     5267        8    65536      280         -1000 systemd-udevd
    Aug 26 22:28:31 localhost kernel: [10811.574949] [    391]   102   391    22557        3    77824      208             0 systemd-timesyn
    Aug 26 22:28:31 localhost kernel: [10811.574950] [    467]   100   467     4602       11    77824      219             0 systemd-network
    Aug 26 22:28:31 localhost kernel: [10811.574952] [    478]   101   478     5974       12    86016     1007             0 systemd-resolve
    Aug 26 22:28:31 localhost kernel: [10811.574953] [    491]     0   491     2111        1    57344      800             0 haveged
    Aug 26 22:28:31 localhost kernel: [10811.574954] [    562]     0   562     1703        0    57344       71             0 cron
    Aug 26 22:28:31 localhost kernel: [10811.574956] [    564]   103   564     1861       13    53248      168          -900 dbus-daemon
    Aug 26 22:28:31 localhost kernel: [10811.574957] [    571]     0   571     7323       66    90112     1896             0 networkd-dispat
    Aug 26 22:28:31 localhost kernel: [10811.574958] [    574]   104   574    56088        0    86016      470             0 rsyslogd
    Aug 26 22:28:31 localhost kernel: [10811.574959] [    577]     0   577     4214        0    73728      242             0 systemd-logind
    Aug 26 22:28:31 localhost kernel: [10811.574960] [    579]     0   579      948        0    45056       57             0 atd
    Aug 26 22:28:31 localhost kernel: [10811.574961] [    640]     0   640     1400        0    49152       33             0 agetty
    Aug 26 22:28:31 localhost kernel: [10811.574963] [    649]     0   649    26977        0   110592     1941             0 unattended-upgr
    Aug 26 22:28:31 localhost kernel: [10811.574964] [    654]     0   654     1457        0    53248       32             0 agetty
    Aug 26 22:28:31 localhost kernel: [10811.574965] [    684]     0   684     3044       12    57344      221         -1000 sshd
    Aug 26 22:28:31 localhost kernel: [10811.574966] [   1322]     0  1322    58179        0    81920      227             0 polkitd
    Aug 26 22:28:31 localhost kernel: [10811.574968] [  12414]   113 12414    53924        4   163840      504          -900 postgres
    Aug 26 22:28:31 localhost kernel: [10811.574969] [  12416]   113 12416    53959        0   172032      532             0 postgres
    Aug 26 22:28:31 localhost kernel: [10811.574970] [  12417]   113 12417    53924        3   155648      512             0 postgres
    Aug 26 22:28:31 localhost kernel: [10811.574971] [  12418]   113 12418    53924        3   147456      511             0 postgres
    Aug 26 22:28:31 localhost kernel: [10811.574973] [  12419]   113 12419    54093        0   159744      608             0 postgres
    Aug 26 22:28:31 localhost kernel: [10811.574974] [  12420]   113 12420    17549       14   126976      528             0 postgres
    Aug 26 22:28:31 localhost kernel: [10811.574975] [  12421]   113 12421    54032        0   151552      583             0 postgres
    Aug 26 22:28:31 localhost kernel: [10811.574976] [  12825]     0 12825     3451        0    61440      367             0 sshd
    Aug 26 22:28:31 localhost kernel: [10811.574978] [  12838]     0 12838     4566        1    77824      363             0 systemd
    Aug 26 22:28:31 localhost kernel: [10811.574979] [  12839]     0 12839    26030        0    98304     1067             0 (sd-pam)
    Aug 26 22:28:31 localhost kernel: [10811.574980] [  12913]     0 12913     2073        0    49152      421             0 bash
    Aug 26 22:28:31 localhost kernel: [10811.574981] [  16980]     0 16980     1378        0    49152       47             0 tail
    Aug 26 22:28:31 localhost kernel: [10811.574983] [  17230]     0 17230     3044        0    69632      225             0 sshd
    Aug 26 22:28:31 localhost kernel: [10811.574984] [  17231]   110 17231     3044        0    69632      226             0 sshd
    Aug 26 22:28:31 localhost kernel: [10811.574985] [  17251]   998 17251   597226   161656  2404352   113716             0 maddy
    Aug 26 22:28:31 localhost kernel: [10811.574987] [  17256]   113 17256    54199       67   167936      698             0 postgres
    Aug 26 22:28:31 localhost kernel: [10811.574988] [  17257]   113 17257    54812      449   184320     1230             0 postgres
    Aug 26 22:28:31 localhost kernel: [10811.574989] [  17291]     0 17291     5267        9    61440      285             0 systemd-udevd
    Aug 26 22:28:31 localhost kernel: [10811.574991] [  17292]     0 17292     5267        2    61440      298             0 systemd-udevd
    Aug 26 22:28:31 localhost kernel: [10811.574993] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/system.slice/maddy.service,task=maddy,pid=17251,uid=998
    Aug 26 22:28:31 localhost kernel: [10811.575012] Out of memory: Killed process 17251 (maddy) total-vm:2388904kB, anon-rss:646624kB, file-rss:0kB, shmem-rss:0kB, UID:998 pgtables:2348kB oom_score_adj:0
    Aug 26 22:28:31 localhost kernel: [10811.656449] oom_reaper: reaped process 17251 (maddy), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
    Aug 26 22:28:31 localhost systemd[1]: maddy.service: Main process exited, code=killed, status=9/KILL
    Aug 26 22:28:31 localhost systemd[1]: maddy.service: Failed with result 'signal'.
    Aug 26 22:28:31 localhost systemd[1]: maddy.service: Scheduled restart job, restart counter is at 15.
    Aug 26 22:28:31 localhost systemd[1]: Stopped maddy mail server.
    

    Configuration file

    maddy.conf
    ## Maddy Mail Server - default configuration file (2021-03-07)
    # Suitable for small-scale deployments. Uses its own format for local users DB,
    # should be managed via maddyctl utility.
    #
    # See tutorials at https://maddy.email for guidance on typical
    # configuration changes.
    #
    # See manual pages (also available at https://maddy.email) for reference
    # documentation.
    
    # ----------------------------------------------------------------------------
    # Base variables
    
    $(hostname) = mx.example.com
    $(primary_domain) = example.com
    $(local_domains) = $(primary_domain)
    
    # debug yes
    
    tls {
        loader acme {
            hostname mx1.example.com
            email [email protected]
            agreed true
            challenge dns-01
            dns cloudflare {
                api_token "..."
            }
        }
    }
    
    # ----------------------------------------------------------------------------
    # Local storage & authentication
    
    # pass_table provides local hashed passwords storage for authentication of
    # users. It can be configured to use any "table" module, in default
    # configuration a table in SQLite DB is used.
    # Table can be replaced to use e.g. a file for passwords. Or pass_table module
    # can be replaced altogether to use some external source of credentials (e.g.
    # PAM, /etc/shadow file).
    #
    # If table module supports it (sql_table does) - credentials can be managed
    # using 'maddyctl creds' command.
    
    auth.pass_table local_authdb {
        table sql_table {
            driver postgres
            dsn "dbname=maddy user=maddy sslmode=disable"
            table_name passwords
        }
    }
    
    # imapsql module stores all indexes and metadata necessary for IMAP using a
    # relational database. It is used by IMAP endpoint for mailbox access and
    # also by SMTP & Submission endpoints for delivery of local messages.
    #
    # IMAP accounts, mailboxes and all message metadata can be inspected using
    # imap-* subcommands of maddyctl utility.
    
    storage.imapsql local_mailboxes {
        driver postgres
        dsn "dbname=maddy user=maddy sslmode=disable"
    
        msg_store s3 {
            endpoint us-east-1.linodeobjects.com
            access_key "..."
            secret_key "..."
            bucket jpatters-email
            region US
        }
    }
    
    # ----------------------------------------------------------------------------
    # SMTP endpoints + message routing
    
    hostname $(hostname)
    
    table.chain local_rewrites {
        optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
        optional_step file /etc/maddy/aliases
    }
    
    msgpipeline local_routing {
        # Insert handling for special-purpose local domains here.
        # e.g.
        # destination lists.example.org {
        #     deliver_to lmtp tcp://127.0.0.1:8024
        # }
    
        destination postmaster $(local_domains) {
            modify {
                replace_rcpt &local_rewrites
            }
    
            deliver_to &local_mailboxes
        }
    
        default_destination {
            reject 550 5.1.1 "User doesn't exist"
        }
    }
    
    smtp tcp://0.0.0.0:25 {
        limits {
            # Up to 20 msgs/sec across max. 10 SMTP connections.
            all rate 20 1s
            all concurrency 10
        }
    
        auth &local_authdb
    
        dmarc yes
        check {
            require_mx_record
            dkim
            spf
        }
    
        source $(local_domains) {
            reject 501 5.1.8 "Use Submission for outgoing SMTP"
        }
        default_source {
            destination postmaster $(local_domains) {
                deliver_to &local_routing
            }
            default_destination {
                reject 550 5.1.1 "User doesn't exist"
            }
        }
    }
    
    submission tls://0.0.0.0:465 tcp://0.0.0.0:587 {
        limits {
            # Up to 50 msgs/sec across any amount of SMTP connections.
            all rate 50 1s
        }
    
        auth &local_authdb
    
        source $(local_domains) {
            check {
                authorize_sender {
                    prepare_email &local_rewrites
                    user_to_email identity
                }
            }
    
            destination postmaster $(local_domains) {
                deliver_to &local_routing
            }
            default_destination {
                modify {
                    dkim $(primary_domain) $(local_domains) default
                }
                deliver_to &remote_queue
            }
        }
        default_source {
            reject 501 5.1.8 "Non-local sender domain"
        }
    }
    
    target.remote outbound_delivery {
        limits {
            # Up to 20 msgs/sec across max. 10 SMTP connections
            # for each recipient domain.
            destination rate 20 1s
            destination concurrency 10
        }
        mx_auth {
            dane
            mtasts {
                cache fs
                fs_dir mtasts_cache/
            }
            local_policy {
                min_tls_level encrypted
                min_mx_level none
            }
        }
    }
    
    target.queue remote_queue {
        target &outbound_delivery
    
        autogenerated_msg_domain $(primary_domain)
        bounce {
            destination postmaster $(local_domains) {
                deliver_to &local_routing
            }
            default_destination {
                reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
            }
        }
    }
    
    # ----------------------------------------------------------------------------
    # IMAP endpoints
    
    imap tls://0.0.0.0:993 tcp://0.0.0.0:143 {
        auth &local_authdb
        storage &local_mailboxes
    }
    

    Environment information

    • maddy version: master
    • system: Ubuntu 20.04 Linode 1 CPU 1GB RAM
    bug storage 
    opened by jpatters 18
  • Strange behaviour with FairEmail Android mail client

    Strange behaviour with FairEmail Android mail client

    Hi!

    image

    I've been getting a weird warning with the FairEmail mail client when refreshing a folder inside it. Folder listings/IMAP keywords/syncing/sending and receiving email all work fine, but the warning persists.

    I was talking to the author of FairEmail regarding the warning to identify the cause as FairEmail works with my 9 other email accounts and I hoped their own analysis would save you time, their response is below after I gave them a test account:

    There are at least protocol bugs because moving (=copy+delete) to the trash folder didn't work as expected.

    06-14 15:26:18.409 13182 30271 I System.out: FX104 STORE 3 +FLAGS (\Deleted) 06-14 15:26:18.425 13182 30271 I System.out: FX104 OK STORE completed 06-14 15:26:18.466 13182 30271 I System.out: FX106 EXPUNGE 06-14 15:26:18.514 13182 30271 I System.out: FX106 OK EXPUNGE completed 06-14 15:26:18.515 13182 30269 I System.out: FX107 IDLE 06-14 15:26:18.516 13182 30269 I System.out: * 3 EXPUNGE

    Yet:

    06-14 15:26:18.791 13182 16353 I System.out: JT3 FETCH 3 (UID) 06-14 15:26:18.806 13182 16353 I System.out: JT3 OK FETCH completed

    JavaMail doesn't handle this properly by returning a uid of -1, but that is another problem.

    I hope that is somewhat helpful to you.

    I really want to move my current setup to Maddy, I have several domains with 30+ mailboxes, with my main mailbox being 99k emails.

    bug go-imap-sql imap 
    opened by yesnomaybeyes 16
  • Per-domain TLS certificates

    Per-domain TLS certificates

    Rationale and possible alternative: https://github.com/foxcpp/maddy/issues/58#issuecomment-506008743

    Guidance for contributors

    Make it possible to specify multiple cert-key pairs in the tls directive:

    tls <cert> <key> <cert> <key>
    

    Load them all then call tls.Config.BuildNameToCertificate.

    The relevant code is in internal/config/tls_server.go in the readTLSBlock function. Documentation to update: docs/man/maddy-imap.5.scd, docs/man/maddy-smtp.5.scd and probably docs/man/maddy-tls.5.scd.

    Original post

    Perhaps something like that:

    tls perdomain {
      <domain> <cert_file> <key_file>
      _default cert_file key_file
    }
    

    Possible using GetCertificate or GetConfigForClient callbacks in tls.Config.

    new feature ready-for-release 
    opened by foxcpp 16
  • DSNs not being received

    DSNs not being received

    Describe the bug

    I don't appear to receive DSNs for any of the following reasons:

    • policy (minimum TLS level) failures that are temporary but last for at least a month
    • recipient doesn't exist
    • remote MTA rejects e-mail because of blacklist

    Oops, should have tested it :sweat_smile: :).

    Steps to reproduce

    • Send an e-mail to [email protected]
    • No DSN is received to inbox, even though the Maddy logs suggest it will be generated

    Log files

    submission: incoming message        {"msg_id":"2f6f32e9","sender":"[email protected]","src_host":"[192.168.1.10]","src_ip":"xxx:47740","username":"[email protected]"}
    submission: RCPT ok        {"msg_id":"2f6f32e9","rcpt":"[email protected]"}
    submission: accepted        {"msg_id":"2f6f32e9"}
    queue: delivery attempt failed        {"msg_id":"2f6f32e9","rcpt":"[email protected]","reason":"Domain does not accept email (null MX)","smtp_code":556,"smtp_enchcode":"5.1.10","smtp_msg":"Domain does not accept email (null MX)"}
    queue: not delivered, permanent error        {"msg_id":"2f6f32e9","rcpt":"[email protected]"}
    queue: generated failed DSN        {"dsn_id":"b77c542c","msg_id":"2f6f32e9"}
    msgpipeline: no check action        {"check":"verify_dkim","msg_id":"b77c542c","reason":"No DKIM signatures","smtp_code":550,"smtp_enchcode":"5.7.20","smtp_msg":"No DKIM signatures"}
    

    Configuration file

    https://hastebin.com/raw/leriyabube

    Environment information

    • maddy version: Maddy says maddy 0.5.0-dev15+ge4ad3bd linux/amd64 go1.14.7 but I actually built it from source from the v0.4.3 release cd1d52764ca8e39233e8a53a831f9066d997b763.

    Notable config changes: I use Dovecot for mailbox handling, could this be related?

    bug mta-out 
    opened by reivilibre 13
  • User doesn't exist Error

    User doesn't exist Error

    Describe the bug

    By following the tutorial I can not make maddy work. I receive "User doesn't exist (msg ID = aa74c9e5)" while sending from maddy (Apple Mail) and "550 5.1.1 User doesn't exist (msg ID = 6b4ebbc6)" reported while sending to the maddy.

    What do you think is wrong?

    I followed the instruction here: https://foxcpp.dev/maddy/tutorials/setting-up/ an I think it should just work.

    I have just changed "dmarc yes" to "dmarc no" and commented the "dkim" in local_routing.

    Steps to reproduce

    follow https://foxcpp.dev/maddy/tutorials/setting-up/

    Log files

    Configuration file

    msgpipeline local_routing {
        dmarc no
        check {
            require_matching_ehlo
            require_mx_record
    #        dkim
            spf
        }
    

    Environment information

    • maddy version: 0.4.0+gf9d5c0c
    question 
    opened by kamarya 12
  • maddy fails to validate SPF record with long lookup chain

    maddy fails to validate SPF record with long lookup chain

    Describe the bug

    When receiving email with a standard-compliant SPF header maddy fails to validate the SPF record because it considers it to have too many lookups. It should fail to deliver the message though since the SPF header is considered valid.

    Steps to reproduce

    The SPF record is considered valid when using popular tools to verify it. It's a rather long chain, but it's compliant as far as I can tell. And yes, it is lacking a valid DKIM signature (and therefore doesn't pass the DMARC check).

    Google's servers are receiving email from the same domain without any issues.

    Log files

    2022-05-15T09:33:06.307Z smtp: incoming message	{"msg_id":"f0359554","sender":"[email protected]","src_host":"mail2.km-it.de","src_ip":"130.180.63.115:37838"}
    2022-05-15T09:33:06.344Z smtp: RCPT ok	{"msg_id":"f0359554","rcpt":"<redacted>"}
    2022-05-15T09:33:06.419Z smtp/pipeline: no check action	{"check":"check.dkim","msg_id":"f0359554","reason":"No DKIM signatures","smtp_code":550,"smtp_enchcode":"5.7.20","smtp_msg":"No DKIM signatures"}
    2022-05-15T09:33:07.652Z smtp: DATA error	{"check":"check.spf","msg_id":"f0359554","reason":"lookup limit reached","smtp_code":550,"smtp_enchcode":"5.7.23","smtp_msg":"SPF authentication failed with a permanent error"}
    

    Configuration file

    $(hostname) = mail.<redacted>
    $(primary_domain) = <redacted>
    $(local_domains) = $(primary_domain)
    
    log stderr_ts
    
    tls file <redacted>
    
    hostname $(hostname)
    
    table.chain local_rewrites {
        optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
        optional_step static {
            entry postmaster postmaster@$(primary_domain)
        }
        optional_step file /etc/maddy/aliases
    }
    
    msgpipeline local_routing {
        destination postmaster $(local_domains) {
            modify {
                replace_rcpt &local_rewrites
            }
    
            deliver_to &local_mailboxes
        }
    
        default_destination {
            reject 550 5.1.1 "User doesn't exist"
        }
    }
    
    smtp tcp://[::]:25 {
        limits {
            # Up to 20 msgs/sec across max. 10 SMTP connections.
            all rate 20 1s
            all concurrency 10
        }
    
        dmarc yes
        check {
            require_mx_record
            dkim
            spf
            rspamd {
                api_path http://rspamd:11332
                io_error_action ignore
                error_resp_action ignore
                add_header_action quarantine
                rewrite_subj_action quarantine
                flags pass_all
            }
        }
    
        source $(local_domains) {
            reject 501 5.1.8 "Use Submission for outgoing SMTP"
        }
        default_source {
            destination postmaster $(local_domains) {
                deliver_to &local_routing
            }
            default_destination {
                reject 550 5.1.1 "User doesn't exist"
            }
        }
    }
    
    submission tcp://[::]:587 {
        auth dovecot_sasl tcp://dovecot:5520
    
        limits {
          all rate 50 1s
        }
    
        source $(local_domains) {
            check {
                authorize_sender {
                    prepare_email &local_rewrites
                    user_to_email identity
                }
            }
    
            destination postmaster $(local_domains) {
                deliver_to &local_routing
            }
            default_destination {
                modify {
                    dkim {
                        domains $(primary_domain) $(local_domains)
                        selector ed25519
                        key_path dkim-keys/{domain}-{selector}.key
                    }
                    dkim {
                        domains $(primary_domain) $(local_domains)
                        selector rsa
                        key_path dkim-keys/{domain}-{selector}.key
                    }
                }
                deliver_to &remote_queue
            }
        }
        default_source {
            reject 501 5.1.8 "Non-local sender domain"
        }
    }
    
    target.remote outbound_delivery {
        limits {
            # Up to 20 msgs/sec across max. 10 SMTP connections
            # for each recipient domain.
            destination rate 20 1s
            destination concurrency 10
        }
        mx_auth {
            dane
            mtasts {
                cache fs
                fs_dir mtasts_cache/
            }
            local_policy {
                min_tls_level encrypted
                min_mx_level none
            }
        }
    }
    
    target.queue remote_queue {
        target &outbound_delivery
    
        autogenerated_msg_domain $(primary_domain)
        bounce {
            destination postmaster $(local_domains) {
                deliver_to &local_routing
            }
            default_destination {
                reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
            }
        }
    }
    
    target.lmtp local_mailboxes {
        targets tcp://dovecot:5500
    }
    

    Environment information

    • maddy version: 0.5.4
    bug release-blocker ready-for-release 
    opened by moritzheiber 11
  • DNS 'server misbehaving' with SPF and DMARC checks (suspected Go bug)

    DNS 'server misbehaving' with SPF and DMARC checks (suspected Go bug)

    When I send an e-mail to my server from, uhhh, 'example.net', Maddy Mail Server temporarily rejects it — keywords are that the lookup returns 'server misbehaving'.

    In the logs, I see

    smtp: RCPT ok        {"msg_id":"cc89eb1d","rcpt":"[email protected]"}
    msgpipeline: no check action        {"check":"verify_dkim","msg_id":"cc89eb1d","reason":"No DKIM signatures","smtp_code":550,"smtp_enchcode":"5.7.20","smtp_msg":"No DKIM signatures"}
    check.spf: DMARC fetch        {"from_domain":"example.net","msg_id":"cc89eb1d","reason":"lookup _dmarc.example.net on 127.0.0.53:53: server misbehaving"}
    smtp: DATA error        {"check":"check.spf","msg_id":"cc89eb1d","reason":"lookup example.net on 127.0.0.53:53: server misbehaving","smtp_code":451,"smtp_enchcode":"4.7.23","smtp_msg":"SPF authentication failed with a temporary error"}
    

    This seems similar to an old issue caused by an issue in Go itself: https://github.com/golang/go/issues/12712 However, that was supposedly fixed in Go 1.6...?

    Note: dig example.net txt suggests that there are no TXT records on that domain.

    Environment

    maddy 0.5.0-dev15+ge4ad3bd linux/amd64 go1.14.3 Ubuntu 20.04.1 (LTS)

    Workaround

    Removing search domains (lines beginning with search) in /etc/resolv.conf and restarting Maddy seems to have worked around the problem.


    Sorry for yet another issue, but even if there's nothing sensible to do about this, I thought it might be nice to have this here so someone else can find it and save themselves half an hour.

    bug rfc 
    opened by reivilibre 11
  • Messages shown twice in Rainloop Webmail

    Messages shown twice in Rainloop Webmail

    Describe the bug

    Messages in Rainloop Webmail is shown twice in all IMAP folders after some manipulations. It's working OK with dovecot, so posting as bug in maddy. If you delete message, both "copies" disappears, and appears in Trash wth same duplicate stuff. Afterlogic webmail is doing same. But Thunderbird / Outlook for Android, shows only one message.

    Example: https://i.imgur.com/yRdvXqk.gif

    Steps to reproduce

    Just view the mail in Webmail.

    Log files

    Nothing wrong with logs.

    Configuration file

    Default config from build.sh with changed hostname and sqlite db.

    Environment information

    maddy 0.3.2+gf720dab linux/amd64 go1.14.3

    default config: /etc/maddy/maddy.conf default state_dir: /var/lib/maddy default runtime_dir: /run/maddy

    bug 
    opened by jeefo 11
  • How to realize the function of mail group?

    How to realize the function of mail group?

    Use case

    What problem you are trying to solve? I want to realize the function of mail group, for example, [email protected], [email protected], When these group emails receive emails, people in the group can also receive emails,how can i do it

    Your idea for a solution

    via alias? Copy the email content to everyone's Maildir. If there are many people, it will take a long time and take up large resources. Is there a better way? Thank you

    • [ ] I'm willing to help with the implementation
    question 
    opened by imzykk 3
  • race condition on table.file

    race condition on table.file

    Describe the bug

    There is a race condition in table.file module. The problem is related to the comment on https://github.com/foxcpp/maddy/blob/master/internal/table/file_test.go#L114

    	// This delay is somehow important. Not sure why.
    	time.Sleep(500 * time.Millisecond)
    

    Steps to reproduce

    go test -run TestFileReload -count 1000
    

    Eventually you will hit the issue and the unit test will fail with:

    --- FAIL: TestFileReload (3.51s)
        file_test.go:134: New m were not loaded
    

    The problem is that in unix/linux OS the code which creates the file is not atomic and therefore there is a race condition that although the code is stat'ing the file it will actually read an empty file instead of the content cat: dog.

    Now the question is how to fix this. It is trivial to fix the unit test in a way that we use the standard procedure to first write a tempfile with the content and then do an atomic rename of the file. This would fix the unit test BUT I think we should actually also fix the real issue in the code e.g. in that it should not only check the last modified date but also whether content is already written to the file.

    • maddy version: master
    bug 
    opened by domcyrus 1
  • verifying github.com/libdns/gandi@v1.0.2: checksum mismatch

    verifying github.com/libdns/gandi@v1.0.2: checksum mismatch

    Describe the bug

    can't build maddy

    Steps to reproduce

    git clone https://github.com/foxcpp/maddy.git
    cd maddy
    ./build.sh
    

    Log files

    -- Version: 0.6.2+e1b3391
    -- Building main server executable...
    go: downloading github.com/caddyserver/certmagic v0.16.1
    go: downloading github.com/urfave/cli/v2 v2.10.2
    go: downloading github.com/foxcpp/go-imap v1.0.0-beta.1.0.20220623182312-df940c324887
    go: downloading github.com/foxcpp/go-imap-sql v0.5.1-0.20220627220518-df3b66a5b04f
    go: downloading golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
    go: downloading github.com/klauspost/cpuid/v2 v2.0.14
    go: downloading github.com/libdns/libdns v0.2.1
    go: downloading github.com/mholt/acmez v1.0.2
    go: downloading github.com/miekg/dns v1.1.50
    go: downloading go.uber.org/zap v1.21.0
    go: downloading golang.org/x/net v0.0.0-20220622184535-263ec571b305
    go: downloading github.com/emersion/go-message v0.16.0
    go: downloading github.com/emersion/go-msgauth v0.6.6
    go: downloading github.com/emersion/go-smtp v0.15.1-0.20220119142625-1c322d2783aa
    go: downloading github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac
    go: downloading github.com/foxcpp/go-dovecot-sasl v0.0.0-20200522223722-c4699d7a24bf
    go: downloading github.com/go-ldap/ldap/v3 v3.4.3
    go: downloading golang.org/x/text v0.3.7
    go: downloading github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962
    go: downloading golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
    go: downloading github.com/emersion/go-milter v0.3.3
    go: downloading blitiri.com.ar/go/spf v1.5.1
    go: downloading github.com/emersion/go-imap-compress v0.0.0-20201103190257-14809af1d1b9
    go: downloading github.com/emersion/go-imap-sortthread v1.2.0
    go: downloading github.com/foxcpp/go-imap-i18nlevel v0.0.0-20200208001533-d6ec88553005
    go: downloading github.com/foxcpp/go-imap-namespace v0.0.0-20200802091432-08496dd8e0ed
    go: downloading github.com/prometheus/client_golang v1.12.2
    go: downloading github.com/google/uuid v1.3.0
    go: downloading github.com/libdns/cloudflare v0.1.0
    go: downloading github.com/libdns/digitalocean v0.0.0-20220518195853-a541bc8aa80f
    go: downloading github.com/libdns/gandi v1.0.2
    verifying github.com/libdns/[email protected]: checksum mismatch
            downloaded: h1:6Z94oPHjL2H+vQoNU4CwZP7C5W0vFnSEyyk+NNyK1Z4=
            go.sum:     h1:1Ts8UpI1x5PVKpOjKC7Dn4+EObndz9gm6vdZnloHSKQ=
    
    SECURITY ERROR
    This download does NOT match an earlier download recorded in go.sum.
    The bits may have been replaced on the origin server, or an attacker may
    have intercepted the download attempt.
    
    For more information, see 'go help module-auth'.
    

    Environment information

    • go version: 1.19.3
    bug 
    opened by wael444 1
  • Maximum length IDNs are not usable

    Maximum length IDNs are not usable

    Describe the bug

    When an IDN is maximum length allowed, it will be rejected by maddy, even if it's otherwise technically usable and allowed.

    For example xn--oaoaaaoaoaoaooaoaoiuaiauiuaiauaaa-f1cadccdcmd01eddchqcbe07a.tld, this is not a real domain just reproduces the problem. It just reaches the maximum length of 63 characters allowed for a label in punycode.

    Steps to reproduce

    Add a maximum length IDN to local_domains

    Log files

    /data/maddy.conf:95: invalid source routing rule: äõäoaõoäaõaäõaoäaoaäõoaäooaoaoiuaiauäõiuüõaõäiauõaaa.tld
    

    Environment information

    • maddy version: 0.6.2
    bug 
    opened by Avamander 1
  • Emails in RainLoop are not displayed

    Emails in RainLoop are not displayed

    Describe the bug

    Hello, emails are not displayed in RainLoop. We can see that RainLoop detects the email (1) in the column, but it is not visible. I have no problem with K-9 Mail.

    Steps to reproduce

    I use the latest version of RainLoop: 1.17.0 Just click on Inbox and see that nothing appears.

    Log files

    I use the default docker configuration with very few changes.

    Log from RainLoop when i click on Inbox :

    imap: * OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR CHILDREN UNSELECT MOVE IDLE APPENDLIMIT STARTTLS LOGINDISABLED COMPRESS] IMAP4rev1 Service Ready
    imap: TAG1 STARTTLS
    imap: TAG1 OK Begin TLS negotiation now
    imap: TAG2 CAPABILITY
    imap: * CAPABILITY IMAP4rev1 LITERAL+ SASL-IR CHILDREN UNSELECT MOVE IDLE APPENDLIMIT AUTH=PLAIN AUTH=LOGIN COMPRESS
    imap: TAG2 OK CAPABILITY completed
    imap: TAG3 AUTHENTICATE PLAIN
    imap: +
    imap: TAG3 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR CHILDREN UNSELECT MOVE IDLE APPENDLIMIT I18NLEVEL=1 SORT THREAD=ORDEREDSUBJECT COMPRESS NAMESPACE] AUTHENTICATE completed
    imap: TAG4 CAPABILITY
    imap: * CAPABILITY IMAP4rev1 LITERAL+ SASL-IR CHILDREN UNSELECT MOVE IDLE APPENDLIMIT I18NLEVEL=1 SORT THREAD=ORDEREDSUBJECT COMPRESS NAMESPACE
    imap: TAG4 OK CAPABILITY completed
    imap: TAG5 STATUS "INBOX" (MESSAGES UNSEEN UIDNEXT)
    imap: * STATUS INBOX (MESSAGES 1 UNSEEN 1 UIDNEXT 2)
    imap: TAG5 OK STATUS completed
    imap: TAG6 LOGOUT
    imap: * BYE Closing connection
    imap: TAG6 OK LOGOUT completed
    

    And no problem from K-9 Mail when i refresh the Inbox folder :

    imap: * OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR CHILDREN UNSELECT MOVE IDLE APPENDLIMIT STARTTLS LOGINDISABLED COMPRESS] IMAP4rev1 Service Ready
    imap: 1 STARTTLS
    imap: 1 OK Begin TLS negotiation now
    imap: 2 CAPABILITY
    imap: * CAPABILITY IMAP4rev1 LITERAL+ SASL-IR CHILDREN UNSELECT MOVE IDLE APPENDLIMIT AUTH=PLAIN AUTH=LOGIN COMPRESS
    imap: 2 OK CAPABILITY completed
    imap: 3 AUTHENTICATE PLAIN
    imap: +
    imap: 3 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR CHILDREN UNSELECT MOVE IDLE APPENDLIMIT I18NLEVEL=1 SORT THREAD=ORDEREDSUBJECT COMPRESS NAMESPACE] AUTHENTICATE completed
    imap: 4 NAMESPACE
    imap: * NAMESPACE (("" ".")) NIL NIL
    imap: 4 OK NAMESPACE completed
    imap: 5 EXAMINE "INBOX"
    imap: * FLAGS (\Seen \Answered \Flagged \Deleted \Draft)
    imap: * OK [PERMANENTFLAGS (\Seen \Answered \Flagged \Deleted \Draft \*)] Flags permitted.
    imap: * OK [UNSEEN 1] Message 1 is first unseen
    imap: * 1 EXISTS
    imap: * 1 RECENT
    imap: * OK [UIDNEXT 2] Predicted next UID
    imap: * OK [UIDVALIDITY 3991729979] UIDs valid
    imap: 5 OK [READ-ONLY] EXAMINE completed
    imap: 6 UID SEARCH 1:1 NOT DELETED
    imap: * SEARCH 1
    imap: 6 OK UID SEARCH completed
    imap: 7 UID FETCH 1 (UID FLAGS)
    imap: * 1 FETCH (UID 1 FLAGS (\Recent))
    imap: 7 OK UID FETCH completed
    

    RainLoop screenshot :

    20221030_01h56m32s_grim

    Configuration file

    ## Maddy Mail Server - default configuration file (2022-06-18)
    ## This is the copy of maddy.conf with changes necessary to run it in Docker.
    # Suitable for small-scale deployments. Uses its own format for local users DB,
    # should be managed via maddyctl utility.
    #
    # See tutorials at https://maddy.email for guidance on typical
    # configuration changes.
    
    # ----------------------------------------------------------------------------
    # Base variables
    
    $(hostname) = test.domain.net
    $(primary_domain) = test.domain.net
    $(local_domains) = $(primary_domain)
    
    tls file /data/tls/fullchain.pem /data/tls/privkey.pem
    
    # ----------------------------------------------------------------------------
    # Local storage & authentication
    
    # pass_table provides local hashed passwords storage for authentication of
    # users. It can be configured to use any "table" module, in default
    # configuration a table in SQLite DB is used.
    # Table can be replaced to use e.g. a file for passwords. Or pass_table module
    # can be replaced altogether to use some external source of credentials (e.g.
    # PAM, /etc/shadow file).
    #
    # If table module supports it (sql_table does) - credentials can be managed
    # using 'maddyctl creds' command.
    
    auth.pass_table local_authdb {
        table sql_table {
            driver sqlite3
            dsn credentials.db
            table_name passwords
        }
    }
    
    # imapsql module stores all indexes and metadata necessary for IMAP using a
    # relational database. It is used by IMAP endpoint for mailbox access and
    # also by SMTP & Submission endpoints for delivery of local messages.
    #
    # IMAP accounts, mailboxes and all message metadata can be inspected using
    # imap-* subcommands of maddyctl utility.
    
    storage.imapsql local_mailboxes {
        driver sqlite3
        dsn imapsql.db
    }
    
    # ----------------------------------------------------------------------------
    # SMTP endpoints + message routing
    
    hostname $(hostname)
    
    table.chain local_rewrites {
        optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
        optional_step static {
            entry postmaster postmaster@$(primary_domain)
        }
        optional_step file /etc/maddy/aliases
    }
    
    msgpipeline local_routing {
        # Insert handling for special-purpose local domains here.
        # e.g.
        # destination lists.example.org {
        #     deliver_to lmtp tcp://127.0.0.1:8024
        # }
    
        destination postmaster $(local_domains) {
            modify {
                replace_rcpt &local_rewrites
            }
    
            deliver_to &local_mailboxes
        }
    
        default_destination {
            reject 550 5.1.1 "User doesn't exist"
        }
    }
    
    smtp tcp://0.0.0.0:25 {
        limits {
            # Up to 20 msgs/sec across max. 10 SMTP connections.
            all rate 20 1s
            all concurrency 10
        }
    
        dmarc yes
        check {
            require_mx_record
            dkim
            spf
        }
    
        source $(local_domains) {
            reject 501 5.1.8 "Use Submission for outgoing SMTP"
        }
        default_source {
            destination postmaster $(local_domains) {
                deliver_to &local_routing
            }
            default_destination {
                reject 550 5.1.1 "User doesn't exist"
            }
        }
    }
    
    submission tls://0.0.0.0:465 tcp://0.0.0.0:587 {
        limits {
            # Up to 50 msgs/sec across any amount of SMTP connections.
            all rate 50 1s
        }
    
        auth &local_authdb
    
        source $(local_domains) {
            check {
                authorize_sender {
                    prepare_email &local_rewrites
                    user_to_email identity
                }
            }
    
            destination postmaster $(local_domains) {
                deliver_to &local_routing
            }
            default_destination {
                modify {
                    dkim $(primary_domain) $(local_domains) default
                }
                deliver_to &remote_queue
            }
        }
        default_source {
            reject 501 5.1.8 "Non-local sender domain"
        }
    }
    
    target.remote outbound_delivery {
        limits {
            # Up to 20 msgs/sec across max. 10 SMTP connections
            # for each recipient domain.
            destination rate 20 1s
            destination concurrency 10
        }
        mx_auth {
            dane
            mtasts {
                cache fs
                fs_dir mtasts_cache/
            }
            local_policy {
                min_tls_level encrypted
                min_mx_level none
            }
        }
    }
    
    target.queue remote_queue {
        target &outbound_delivery
    
        autogenerated_msg_domain $(primary_domain)
        bounce {
            destination postmaster $(local_domains) {
                deliver_to &local_routing
            }
            default_destination {
                reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
            }
        }
    }
    
    # ----------------------------------------------------------------------------
    # IMAP endpoints
    
    imap tls://0.0.0.0:993 tcp://0.0.0.0:143 {
        debug
        io_debug
        auth &local_authdb
        storage &local_mailboxes
    }
    

    Environment information

    Alpine Linux 3.16.2 Podman 4.1.0

    • maddy version: docker foxcpp/maddy:0.6.2
    bug 
    opened by tetsumaki 2
Releases(v0.6.2)
  • v0.6.2(Jul 1, 2022)

    Bugfixes

    • Fix empty IMAP folders being shown sometimes (https://github.com/foxcpp/maddy/issues/512)
    • Fix maddyctl imap-msgs lists crash (https://github.com/foxcpp/maddy/issues/509)
    • Fix maddyctl imap-msgs remove being no-op (https://github.com/foxcpp/maddy/issues/510)
    • pass_table: fix user hash creation (https://github.com/foxcpp/maddy/pull/507)

    Docs

    • Update Arch repository and Docker instructions links

    Misc

    • cli: Warn about upcoming --uid=true change
    Source code(tar.gz)
    Source code(zip)
    maddy-0.6.2-src.tar.zst(369.83 KB)
    maddy-0.6.2-src.tar.zst.sig(119 bytes)
    maddy-0.6.2-x86_64-linux-musl.tar.zst(15.43 MB)
    maddy-0.6.2-x86_64-linux-musl.tar.zst.sig(119 bytes)
  • v0.6.1(Jun 23, 2022)

    ⚠️ Release is recalled due to severe issues. Use 0.6.2 instead.

    Bugfixes

    • Fixed missing IMAP IDLE capability, again... (https://github.com/foxcpp/maddy/issues/504)
    • Fixed broken storage.imapsql schema upgrade

    Broken storage.imapsql schema upgrade

    If you happen to run 0.6.0 and got error about schema being too old, you need to run the following SQL query on your imapsql.db before you will be able to use 0.6.1:

    UPDATE schema_version SET version = 6;

    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Jul 8, 2022)

    ⚠️ Release is recalled due to severe issues. Use 0.6.2 instead.

    Breaking changes

    • check: Remove require_matching_echo (deprecated in 0.5) (https://github.com/foxcpp/maddy/issues/280)
    • modify/dkim: Remove require_sender_match from code (https://github.com/foxcpp/maddy/issues/465)

    New features

    • maddyctl and maddy executables are merged

    To start the server: maddy run ... Other maddyctl subcommands are available similiarly: maddy imap-acct, etc

    • Support 1-N recipient address expansion (https://github.com/foxcpp/maddy/issues/401)

    For example, when using table.regexp:

    replace_rcpt regexp "root@(.+)" "admin1@$1" "admin2@$1"
    

    Or table.file:

    [email protected]: [email protected], [email protected]
    

    For SQL-based tables, just add multiple rows with the same key (address to be replaced).

    • Add more placeholders for imap_filter (PR https://github.com/foxcpp/maddy/pull/449)

    {rcpt_to} (SMTP RCPT TO), {original_rcpt_to} (SMTP RCPT TO before any local rewrites), {subject}.

    • storage/imapsql: Add support for using PostgreSQL broker for updates

    It is used automatically, so now it is safe run multiple maddy server instancesusing the same PostgreSQL DB.

    Bugfixes

    • Migrate to go-imap v2 (https://github.com/foxcpp/maddy/issues/188)

    go-imap v2 is my fork of emersion/go-imap library that makes massive changes to the server code.

    In particular, it fixes long-standing issue of update handling being non conforming to RFC 3501.

    • check/spf: Fix "lookup limit reached" for some conforming records (https://github.com/foxcpp/maddy/issues/487)
    • cmd/maddyctl: Fix --argon2-time setting memory instead of time (PR https://github.com/foxcpp/maddy/pull/502)
    • check/spf: Ignore SPF permerr and temperr by default (https://github.com/foxcpp/maddy/issues/485)
    • Move closing the default logger after printing configuration errors
    • Fix TLS Internal Error caused by SNI-unuware clients when ACME is used (https://github.com/foxcpp/maddy/issues/467)

    Documentation changes

    • docs: Add Docker-specific documentation
    • docs: Convert manual pages into per-module Markdown pages

    Misc

    • Go 1.17 is required now
    • Dockerfile: Use TLS filenames same as certbot (https://github.com/foxcpp/maddy/issues/350)
    • Dockerfile: Put Docker-specific config in the repo
    • ci: Set OCI labels in built Docker image
    • ci: Use docker buildx and qemu to build ARM64 images (https://github.com/foxcpp/maddy/issues/404)
    Source code(tar.gz)
    Source code(zip)
  • v0.5.4(Mar 6, 2022)

  • v0.5.3(Feb 16, 2022)

    Docker image changes

    maddy image is now also available at ghcr.io registry:

    docker pull ghcr.io/foxcpp/maddy:0.5
    

    Currently this is just an experiment, we are not sure if we will fully migrate to it.

    Image tags no longer include v prefix with the exception of v0.5 still being updated to maintain compatibility for people that use this tag.

    docker pull foxcpp/maddy:0.5.3 # instead of foxcpp/maddy:v0.5.3
    

    Bug fixes

    • Fix errors from LMTP downstream being ignored (https://github.com/foxcpp/maddy/issues/453)
    • Make it possible to use dovecot_sasl auth with TCP sockets (https://github.com/foxcpp/maddy/pull/450, thanks @JonLundy)
    • Fix MAIL after STARTTLS causing panic
    • Fix IMAP IDLE capability missing (https://github.com/foxcpp/maddy/issues/446)

    Misc

    • Add target.remote force_ipv4 option (https://github.com/foxcpp/maddy/pull/442, thanks @delthas)
    Source code(tar.gz)
    Source code(zip)
    maddy-0.5.3-src.tar.zst(362.90 KB)
    maddy-0.5.3-src.tar.zst.sig(119 bytes)
    maddy-0.5.3-x86_64-linux-musl.tar.zst(28.99 MB)
    maddy-0.5.3-x86_64-linux-musl.tar.zst.sig(119 bytes)
  • v0.5.2(Oct 11, 2021)

  • v0.5.1(Sep 22, 2021)

    Bug fixes

    • table/sql_table: Fix incorrect for PostgreSQL type being used in table creation (GH #386)
    • endpoint/smtp: Fix limitedReader causing message body read to loop forever (GH #403, GH #389)
    • storage/blob/s3: Fix PutObject goroutines leaking if message write is aborted (GH #395)
    • storage/blob/s3: Force a smaller PartSize when blob size is unknown (GH #395)
    • storage/blob: Pass blobSize to go-imap-sql (GH #395)
    • storage/blob/s3: Correctly handle PutObject errors (GH #387)

    Misc

    • libdns: Add namecheap provider (GH #392)

    Added only if maddy is built with Go 1.16.

    • Add postmaster address rewrite back to default config (GH #384)
    Source code(tar.gz)
    Source code(zip)
    maddy-0.5.1-src.tar.zst(3.32 MB)
    maddy-0.5.1-x86_64-linux-musl.tar.zst(28.96 MB)
    maddy-0.5.1-x86_64-linux-musl.tar.zst.sig(119 bytes)
    SHA256SUMS(194 bytes)
    SHA256SUMS.sig(119 bytes)
    maddy-0.5.1-src.tar.zst.sig(119 bytes)
  • v0.5.0(Aug 9, 2021)

    New features

    • Experimental: Built-in ACME client (GH #3)

    Currently supports only dns-01 challenge with a limited set of providers. See documentation for details.

    • S3-backed storage for message contents (GH #304)

    • Local sender authorization (GH #268)

    • LDAP BindDN authentication (GH #273)

    • storage/imapsql: Implement auth_map

    • storage/imapsql: Implement delivery_map

    This functionality allows imapsql storage backend to be correctly used with non-email-based authentication providers. In particular, this unbreaks PAM and shadow modules.

    • Implement table.chain module

    • Implement table.email_localpart as a helper to strip domain from emails

    Improvements

    • Implement client timeouts for target.remote and target.smtp
    • endpoint/smtp: Add max_header_size

    Fixes

    • check/spf: Change default action for softfail to 'ignore'
    • endpoint/smtp: Allow to change the line length limit enforced by go-smtp
    • table/sql_query: Allow to use numbered parameters in queries
    • auth/plain_separate: Make configuration directives actually work
    • table/file: Allow table to be created without specifying files in inline args
    • config/tls: Fix custom loader configuration reading

    Removed functionality

    • check/dns: Mark require_matching_echo as deprecated
    • config/tls: Remove deprecated "tls CERT KEY" syntax
    • Remove deprecated 0.3 module name aliases
    Source code(tar.gz)
    Source code(zip)
    maddy-0.5.0-src.tar.zst(363.55 KB)
    maddy-0.5.0-src.tar.zst.sig(119 bytes)
    maddy-0.5.0-x86_64-linux-musl.tar.zst(28.91 MB)
    maddy-0.5.0-x86_64-linux-musl.tar.zst.sig(119 bytes)
  • v0.4.4(Apr 11, 2021)

    The long awaited release!

    Outbound SMTP

    • target/remote: Force MX domain to be FQDN when looking up TLSA records (GH #321)
    • Fix two issues in handling of DSN messages in SMTP pipeline and checks (GH #327)
    • dns: Attempt to use 127.0.0.1 if no DNS servers are configured in system
    • target/queue: Do not attempt to do atomic overwrite for metadata on Windows (GH #334)

    Inbound SMTP

    • endpoint/smtp: Unbreak MAIL FROM:<> handling (GH #337)
    • endpoint/smtp: Release Msg limiter correctly if pipeline.Start fails (GH #348)

    Misc

    • config/tls: Fix tls_client parsing (Thanks @AluisioASG!)

    Documentation

    • docs: Replace foxcpp.dev/maddy with maddy.email
    • docs: Remove reference to local_modifiers from multiple-domains.md
    • docs: fixed small error (Thanks @0xflotus!)
    • Fix a typo in maddy-smtp man doc (Thanks @Defman21!)

    Docker

    This release changes how Docker image is built reverting default directories behavior to what 0.4.2 did but implemented in a different way so we have the best of both worlds.

    build.sh

    • Allow setting build tags
    • Do not try to install man pages if they were not built

    3rd party libraries

    • go-smtp now uses Postfix success responses
    • go-msgauth/dkim now supports both RSA public key formats (see https://github.com/emersion/go-msgauth/issues/43)
    Source code(tar.gz)
    Source code(zip)
    maddy-0.4.4+dcdf4a7-x86_64-linux-musl.tar.zst(24.38 MB)
    maddy-0.4.4-src.tar.zst(327.09 KB)
    maddy-0.4.4+dcdf4a7-x86_64-linux-musl.tar.zst.sig(119 bytes)
    maddy-0.4.4-src.tar.zst.sig(119 bytes)
  • v0.4.3(Dec 13, 2020)

    GitHub is having troubles with our tarballs again, as usual, binary artifacts are also available at https://foxcpp.dev/maddy-builds/0.4.3/.

    Changes

    SMTP server

    • Auto-buffer code no longer truncates large messages;
    • DANE implementation has been rewritten from scratch to fix many issues; Thanks @vdukhovni!
    • Domains in envelope addresses and EHLO are now always treated as FQDN to avoid quirks when system has search domains configured;
    • target.lmtp no longer attempts to use STARTTLS by default;
    • allow_body_subset directive has been removed from check.dkim code since it is no longer supported upstream;
    • A bug has been fixed in the DKIM canonicalization code that caused some messages to be signed or verified incorrectly (go-msgauth issue);
    • Fix target.lmtp actually acting as target.smtp when defined in a top-level config; Thanks @reivilibre!

    IMAP server

    • HZ-GB-2312 encoding collation support is reenabled. Upstream security issue has been fixed;

    build.sh

    build.sh script has been replaced with a much more simple implementation that works with any POSIX shell and is more portable in general.

    Thanks @Binklebonk, @hugmouse and @herbygillot for helping testing it on non-Linux platforms.

    Misc

    • All uses of deprecated 0.3 module names have been replaced with up-to-date names;

    Documentation

    • Dovecot integration tutorial has been updated to avoid circular dependency in startup; Thanks @reivilibre!
    • All uses of deprecated 0.3 module names have been replaced with up-to-date names; Thanks @reivilibre for spotting some of them!
    Source code(tar.gz)
    Source code(zip)
    maddy-0.4.3-src.tar.zst(327.34 KB)
    maddy-0.4.3-src.tar.zst.sig(119 bytes)
  • v0.4.2(Nov 21, 2020)

    Users of binary packages or Docker image are encouraged to upgrade to get a fix for CVE-2020-28362 that comes with Go 1.15.5

    Note: Binary artifacts for this release were removed due to being broken. Source build should be used.

    Fixes

    • check/milter: Add missing handler for milter.ActTempFail ('t') (thanks @hugmouse!)
    • msgpipeline: Fix log messages missing for sub-pipelines
    • msgpipeline: Fix effective_rcpt in log messages being wrong when sub-pipelines do rewriting
    • endpoint/smtp: Fix handling of empty messages in auto-buffer code
    • endpoint/smtp: Auto-create directory for "fs" buffer mode
    Source code(tar.gz)
    Source code(zip)
    maddy-0.4.2-src.tar.zst(322.94 KB)
    maddy-0.4.2-src.tar.zst.sig(119 bytes)
  • v0.4.1(Oct 23, 2020)

  • v0.4.0(Aug 23, 2020)

    GitHub is having problems uploading artifacts, grab them from https://foxcpp.dev/maddy-builds/0.4.0/

    GPLv3

    After short discussion and collecting necessary agreements, decision was made to change Maddy Mail Server source code license to GNU Public License Version 3.

    See GH#253 for details.

    Deprecated functionality, breaking changes for 0.5

    Work is being done to stabilize maddy interfaces including configuration format and all data structures. Therefore, since 0.4, development strictly follows Semantic Versioning 2, in particular - all breaking changes are announced in advance as "deprecated" before actual change happens. Therefore, this version does not include any breaking changes but 0.5 will.

    • A lot of modules have been renamed to match "namespaced" modules proposal. Warning with correct names will be printed on start with config using old names.

    • STARTTLS Everywhere list support is deprecated and is replaced with no-op stub.

    • TLS certificate loading has been moved to use modules framework. "tls CERT KEY" will need to be changed to "tls file CERT KEY".

    New features

    • Expose performance and usage statistics in OpenMetrics (Prometheus) format. See openmetrics.md.

    • Allow external commands to be used for overwriting IMAP folder and flags on delivery. See GH#202 and maddy-imap(5) for details.

    • Directly integrate with rspamd using its HTTP protocol instead of shell script + rspamc.

    • Reuse SMTP connections to MXs to avoid unnecessary handshake overhead when sending a lot of messages to a single domain. (experimental)

    • Implement server-side SNI support - multiple certificate-key pairs can be specified with "file" loader.

    Enhancements

    • Implement SMTP REQUIRETLS extension

    • imapsql: Implement SORT and THREAD=ORDEREDSUBJECT extensions (experimental)

    • endpoint/imap: Implement NAMESPACE extension

    • imapsql: Fix flags-only search returning duplicate IDs (GH#251)

    • msgpipeline: Permit duplicate destination/source rules

    • table: Allow using regexp table without replacement specified

    • build.sh: Add ability to set build tags

    • build.sh: Add sudo checks (thanks @hugmouse!)

    • check/spf: Make sure error value from library is always reported in logs

    • config/tls: Remove unnecesary GODEBUG setting code

    Bug fixes

    • imapsql: Improve meta-data loading perfomance for Thunderbird by properly caching X-Priority field

    • Fix SPF policy parser bug resulting in false permerror on some ip6 rules (#254)

    • storage/imapsql: Fix incorrect module name in log messages related to delivery errors

    Documentation

    • Add page on Mailman 3 integration

    • Add page on rspamd integration

    • Split maddy(1) and maddy(5)

    • Improve setting-up.md (thanks @schrodinger)

    • Remove fail2ban from initial configuration

    • Clarify configuration for multiple domains

    Source code(tar.gz)
    Source code(zip)
    maddy-0.4.0+gf9d5c0c-x86_64-linux-musl.tar.zst.sig(119 bytes)
    maddy-0.4.0-src.tar.zst.sig(119 bytes)
  • v0.3.3(Jul 24, 2020)

    Note: We are in the progress of changing maddy source code license from MIT to GPLv3. This is the last release to have all code available under MIT license.

    Note: GitHub refused to accept maddy-0.3.3+gd95e4f9-x86_64-linux-musl.tar.zst attachment. A good reminder that artifacts for all releases are available from https://foxcpp.dev/maddy-builds/

    Bug fixes

    • Fix CRLF mangled into LF by net/textproto and incorrect RFC822.SIZE reported by go-imap-sql as a result of that. (18657def692614a487c56eb5d387c73a568a4b88)

    • Fix maddyctl imap-msgs list showing only the last message by default (b2b38bffa7e5c411740b3bf1d61f7a9f87c6503e)

    • Fix attachments reported as 0 bytes (fb2b3a56bc8db0580aafadf0c15e19f69174f582)

    • Fix messages listed twice by RainLoop (abba51612d36a0ea0e7640b4d0b71ffcec2dd846)

    • Fix maddyctl creds set-password being no-op (78f77136e24e916f49f1e9d5407f18a3630efe8f)

    • Mangle CRLF in Diagnostic-Code DSN field (18657def692614a487c56eb5d387c73a568a4b88, see GH#245)

    • Add missing msg_id field for 'RCPT error' message (20fe5ad376614fbb802a84d23f85da42486e05fe)

    • Fix SMTP enhanced code included in extra lines of multi-line SMTP status (18657def692614a487c56eb5d387c73a568a4b88)

    Misc

    • Hide "operation was canceled" errors for async rDNS lookup (fcebfa2d3adf02392598fc20b38354dfd9f7f17a)
    Source code(tar.gz)
    Source code(zip)
    SHA256SUMS(203 bytes)
    SHA256SUMS.sig(119 bytes)
    maddy-0.3.3+gd95e4f9-x86_64-linux-musl.tar.zst.sig(119 bytes)
    maddy-0.3.3-src.tar.zst(283.74 KB)
    maddy-0.3.3-src.tar.zst.sig(119 bytes)
  • v0.3.2(Jun 18, 2020)

    SECURITY ISSUES

    • Update golang.org/x/text to v0.3.3 (fixes potential DoS)

    See CVE-2020-14040 and https://go-review.googlesource.com/c/text/+/238238 for details.

    Bug fixes

    For imapsql IMAP backend:

    • Fix handling of * seqset
    • Add missing counters update for EXPUNGE Thanks @yesnomaybeyes for helping in issue investigation.
    • Do not assume clients specify date in APPEND command
    • Fix creating index on MySQL (https://github.com/foxcpp/go-imap-sql/pull/31) Thanks @wjywbs.

    Documentation changes

    • Extend copyright notice to include contributors
    • Fix formatting and fix possibly confusing MTA-STS example
    • Fix wrong name of 'targets' directive for smtp_downstream

    Misc

    • build.sh: Do not switch to X.Y-fixes branch if version is manually selected
    • dist: Add missing [Install] section to systemd units

    Build artifacts

    | Artifact | SHA-256 | | --- | ----------- | | maddy executable (Linux, x86_64, musl) | b5789e134cab2d79369ffcb3f2150055761611df136493a161b157c3953f9cac | | maddyctl executable (Linux, x86_64, musl) | ba348e548bd417891a6d0314226511e35256b075eb8bc5d5d7cccbe94cfdee11 | | Full Zstd tarball (Linux, x86_64, musl) | d9d059306f1902b7329027136835fea9374d315b6a3f6176c62838d296b653d3 | | Source code tarball | 38d2e6461bf2e21747dfb8d8c1ce5ed3c4d57c5e3eb4327e336c275cd71fbdf9 |

    :lock: Attached tarballs are signed using PGP key 3197 BBD9 5137 E682 A597 17B4 34BB 2007 0813 96F4

    Source code(tar.gz)
    Source code(zip)
    maddy-0.3.2+gf720dab-x86_64-linux-musl.tar.zst(25.88 MB)
    maddy-0.3.2+gf720dab-x86_64-linux-musl.tar.zst.sig(119 bytes)
    maddy-0.3.2-src.tar.zst(283.68 KB)
    maddy-0.3.2-src.tar.zst.sig(119 bytes)
    SHA256SUMS(203 bytes)
  • v0.3.1(Jun 2, 2020)

    Bug fixes

    • limits: Fix "rate" directive parser handling for 2 arguments
    • endpoint/smtp: Fix panic if connection is closed in the middle of receiving body
    • endpoint/smtp: Fix limit leak in case of aborted transaction

    Documentation improvements

    • Change github to github.com in 0.3 migration guide (#237)
    • Mention per-source domain limiting option

    Misc

    • build.sh: Switch to X.Y-fixes branch if it exists
    Source code(tar.gz)
    Source code(zip)
    SHA256SUMS(90 bytes)
    maddy-0.3.1-src.tar.zst(284.74 KB)
    maddy-0.3.1-src.tar.zst.sig(119 bytes)
  • v0.3.0(May 31, 2020)

    Stability: This version is believed to be stable enough for use in use non-critical deployments.

    Breaking changes

    • Minimal supported Go version is increased to Go 1.14

    maddy keeps tracking latest Go version to benefit from language and library improvements.

    build.sh script will automatically download a newer toolchain version if system installed version is too old.

    • Fully separate authentication from IMAP access

    Now there is no uniform database that is used both for IMAP index and authenticaiton. This allows completely independent implementation and leveraging of maddy modular framework for more flexible authentication documentation.

    This is a breaking change that also affects how password hashes are calculated and requires destructive changes to databases created in 0.2 order to use with 0.3. A migration utility is created to assist with that. See Upgrading page in documentation for detailed instructions.

    New features

    • Preliminary milter client implementation

    This release introduces limited implementation of milter client protocol. Due to a number of differences between how maddy handles internal filtering and protocol model "milters" currently cannot make most modifications to the message content and is limited to prepending headers and quarantining or rejecting message.

    • source_in, destination_in directives for message pipeline

    Directives source_in and destination_in allow matching of message senders or recipients against lists sources from table modules (files, SQL queries, etc). See maddy-smtp(5) for details.

    • Dovecot authentication client support

    maddy now implements client side of Dovecot authentication protocol allowing it to be used with Dovecot as an IMAP server instead of builtin server.

    • Dovecot-compatible sasld endpoint

    Additional, maddy also implements Dovecot-compatible sasld endpoint that allows it to be used as a source for authentication data for other servers that support Dovecot authentication protocol (e.g. SMTP servers like Postfix).

    • lmtp_downstream delivery target

    maddy now has full implementation of LMTP client allowing messages to be forwarded to other software that speaks LMTP protocol.

    • endpoint/smtp: Allow to choose the IP to use for outbound smtp.

    • modify/dkim: Allow to sign emails from subdomains using a top domain key

    Improvements

    • cmd/maddyctl: Create a set of typical mailboxes on IMAP account creation
    • endpoint/smtp: Send 535 on permanent authentication failure
    • target: Make Received generation more robust in case of missing data
    • config: Support scheme:IP:PORT syntax for endpoint declaration

    Bug fixes

    • storage/imapsql: Fix SPECIAL-USE support being accidentally disabled
    • Fix and improve -v flag description
    • endpoint/smtp: Fix missing server hostname in Received header
    • target/remote: Do not fail delivery with null return path

    Documentation improvements

    • Fix a number of links in documentation
    • Add page about IMAP-only configuration
    • Mention disabled HZGB2312 support
    • Add smtp-only.md page
    • Add imap-only.md page
    • Add FAQ page
    • Add upgrading instructions page

    Build artifacts

    There is no binary tarballs for this release as Alpine Linux 3.12 ships Go 1.13. This will be addressed in the future and this release will be amended.

    :lock: Attached tarballs are signed using PGP key 3197 BBD9 5137 E682 A597 17B4 34BB 2007 0813 96F4

    Source code(tar.gz)
    Source code(zip)
    SHA256SUMS(90 bytes)
    maddy-0.3.0-src.tar.zst(283.72 KB)
    maddy-0.3.0-src.tar.zst.sig(119 bytes)
  • v0.2.1(May 14, 2020)

    Stability: This version is believed to be stable enough for use in use non-critical deployments.

    SECURITY ISSUES

    • Fixed out-of-memory crash triggered by buggy encoding implementation (8edcd9183df6ca53e2872367632b18b1cc0461ab) (see GHSA-8jp9-qm2r-p877)

    If you require hz-gb-2312 handling and understand security consequences, manually build maddy 0.2.1 with -tags hz_gb_2312 passed to go build command.

    Bug fixes

    • dist: Remove unnessecary log prefix matching for fail2ban filter (979effb4597e229837b4c155d736aa11d30acc50) Thanks @bn4t!

    • check/dkim: Fix a couple of issues in error handling (076fc0d508f3116c1fc54b886ac62e1d3ae24e34)

      DKIM signatures with missing required fields were still considered passing for purposes of action selection.

      dkim.IsPermFail/dkim.IsTempFail calls were checking the wrong error object.

    • storage/imapsql: Fix Close deadlock in case of EnableUpdatePipe fail (96a3b964485e17cb4d97481660b42557fafd5c58)

    • Fix inconsistency in SASLAuth logger name for endpoints (6b87eb98eb0451a84c8b91dd1dce461bedd59d47) (#221)

    • log: Strip extra newline from Logger.Write output (ebccff03ae11ed00bc30cb266df0a55d12941923)

    Documentation improvements

    • Add missing packages for compilation and fail2ban setup (cfe34368f7181b41d6560812f9fcb83cf8d85b3f) Thanks @bn4t!

    • Fix small typo (b96acd5259fa8d30989000bc2a1bfa8c089c158c) Thanks @bn4t!

    • Clarify SECURITY.md (244b03005124ebb131ed1ae8621f598a8ddff285)

    • Update outdated tutorials (b472734713f039300de56867aada6c4e1319b2ac)

    Build artifacts

    | Artifact | SHA-256 | | --- | ----------- | | maddy executable (Linux, x86_64, musl) | 443dfa57f3e5e39ad4130389d439627c2efecba68ac4c9991c4a7cb54c3ce59a | | maddyctl executable (Linux, x86_64, musl) | b9fafcd302f9c55053a2c8609a9b9dd72ab185d332c436b4c2942a79afa7ef99 | | Full Zstd tarball (Linux, x86_64, musl) | b64fcefe64eb081ac1a67c8e38c218c76115014f3d7dcafb7e0a35414faafeb7 | | Source code tarball | a634e054bf3766816643028a5e302c27ec9ddd391fd2a13f12b6959aa86b38e9 |

    :lock: Attached tarballs are signed using PGP key 3197 BBD9 5137 E682 A597 17B4 34BB 2007 0813 96F4

    Build artifacts are produced using the same environment as 0.1.

    Source code(tar.gz)
    Source code(zip)
    SHA256SUMS(203 bytes)
    maddy-0.2.1+g8edcd91-x86_64-linux-musl.tar.zst(24.43 MB)
    maddy-0.2.1+g8edcd91-x86_64-linux-musl.tar.zst.sig(119 bytes)
    maddy-0.2.1-src.tar.zst(263.12 KB)
    maddy-0.2.1-src.tar.zst.sig(119 bytes)
  • v0.2.0(Mar 26, 2020)

    Stability: This version is believed to be stable enough for use in use non-critical deployments. Database structure for sql (imapsql) module is compatible with 0.1. Configuration requires some changes.

    Incompatible changes & migration notes

    • alias_file is replaced with generic replace_rcpt module that can use any "table"-like structure for lookups. Migration: Replace alias_file /etc/maddy/aliases with replace_rcpt file_table /etc/maddy/aliases.

    • replace_rcpt now relies on tables to handle regexp and static replacements. Migration: Replace replace_rcpt postmaster postmaster@$(primary_domain) with replace_rcpt static { entry postmaster postmaster@$(primary_domain). Replace replace_rcpt "(.+)\+(.+)@(.+)" "$1@$3" with replace_rcpt regexp "(.+)\+(.+)@(.+)" "$1@$3".

    • Module sql is renamed to imapsql. Change its name in the configuration block definition for local_mailboxes/local_authdb.

    • Configuration parser now requires a new line after } closing the block.

    New features

    • Authentication code is refined and generalized. It permits the implementation of additional more complex SASL mechanisms such as TLS client certificate authentication and OAuth2 support. These are not implemented in 0.2 though. What is currently accessible is the ability to use multiple password-based authentication providers to allow user login based on any match from any credentials store configured.

    • Generic Postfix-like string lookup abstraction is introduced. Alias rewriting is updated to use. Additionally, it is possible to use it for password-based authentication now. Currently implemented "tables" are: identity (returns the lookup key), dummy (empty table), sql_table (returns the result of a SQL query), static (hardcoded mapping), regexp (Regular Expression-based rewrite of lookup key).

    • sign_dkim module now supports multiple domains in a single configuration, avoiding the need for complex dispatching.

    • maddy -v output now includes compile-time defaults for state_dir, runtime_dir and configuration path.

    • build.sh script can now customize default values for state_dir and runtime_dir.

    Bug fixes

    • Fix race in file_table reload test (a91d8c2)
    • Fix misuse of TriesCount in queue (ceda725)
    • Fix queue retry delay calculation (4b3e7ce)

    Build artifacts

    | Artifact | SHA-256 | | --- | ----------- | | maddy executable (Linux, x86_64, musl) | b9a5c29c50575f63e3b3de7b8ad0380917ff568560da3860580186c53be89304 | | maddyctl executable (Linux, x86_64, musl) | 7bc9ac4cf62e8317a2ef0fa6ff3a8cde6877a2f972c94c1bcbd8f8f0bd4c148e | | Full Zstd tarball (Linux, x86_64, musl) | 154617ed5a9314947c67272edc2a884e0df4664e537816ae6da832f30e00d5dc | | Sourec code tarball | 6f3799d8158d5b9e4625084ab6548fc70c98acdc0234e2acac7e05e553753753 |

    :lock: Attached tarballs are signed using PGP key 3197 BBD9 5137 E682 A597 17B4 34BB 2007 0813 96F4

    Build artifacts are produced using the same environment as 0.1.

    Source code(tar.gz)
    Source code(zip)
    maddy-0.2.0+gb54c705-x86_64-linux-musl.tar.zst(24.44 MB)
    maddy-0.2.0+gb54c705-x86_64-linux-musl.tar.zst.asc(228 bytes)
    maddy-0.2.0-src.tar.zst(262.88 KB)
    maddy-0.2.0-src.tar.zst.asc(228 bytes)
    SHA256SUMS(203 bytes)
  • v0.1.1(Mar 5, 2020)

    This release includes no server code changes.

    Known issues

    • Delay between outbound delivery attempts is improperly calculated and has no effect. Fixed on development branch. Set low outbound rate limit as a workaround for 0.1:

      limits outbound_limits {
          destination rate 1 1m
      }
      
    • Outbound delivery will be attempted more than allowed by max_tries (by 1). Fixed on development branch.

    • build.sh script bundled with 0.1 fails if the system Go toolchain lacks the patch version number (e.g. 1.14). Fixed on development branch. The fixed version is uploaded to foxcpp.dev.

    It is possible to install the in-development version by adding --gitversion flag to the build.sh script invocation:

    curl 'https://foxcpp.dev/maddy/build.sh' | bash /dev/stdin --gitversion dev
    

    Change log

    Documentation

    • Mention prebuilt binaries in the setup tutorial
    • Be more specific about build.sh dependencies
    • Remove "in early development" disclaimers
    • Several minor edits (8f1d57293cb2135da75503e853101d8e0b7f3743)

    Build script (build.sh)

    • Use absolute path to the Go toolchain in PATH
    • Check GOMOD value correctly
    • Remove wget dependency

    Build artifacts

    | Artifact | SHA-256 | | --- | ----------- | | maddy executable (Linux, x86_64, musl) | dc7db76d9adba8c4a60893534eb41fb0941717f53954f87f70a5066fc43cc207 | | maddyctl executable (Linux, x86_64, musl) | ffbcc615d343af1196635aac5e229c8e6f9bf5459eabfeae8cd2404c1ec103e3 | | Full Zstd tarball (Linux, x86_64, musl) | 4380a2eda129987333db3fd2b4e493de62200aa4f717ea8f67789da4cb21472f | | Source code tarball | bf155f17eda6df20b435ba6e7a2ffce773b146e2a8b9eb8bc2c7d2a02176a8db |

    :lock: Attached tarballs are signed using PGP key 3197 BBD9 5137 E682 A597 17B4 34BB 2007 0813 96F4

    Build environment is the same as the previous release (0.1).

    Source code(tar.gz)
    Source code(zip)
    SHA256SUMS(208 bytes)
    maddy-v0.1.1.r0.g8f1d572-x86_64-linux-musl.tar.zst(24.30 MB)
    maddy-v0.1.1.r0.g8f1d572-x86_64-linux-musl.tar.zst.asc(228 bytes)
    maddy-v0.1.1-src.tar.zst(255.13 KB)
    maddy-v0.1.1-src.tar.zst.asc(228 bytes)
  • v0.1.0(Feb 22, 2020)

    Stability: This version is believed to be stable enough for use in use non-critical deployments. Backward compatibility for database structures and configuration syntax is not promised but will be maintained if possible.

    Implemented features

    • IMAP4rev1 (RFC 3501) server implementation with some basic extensions
    • SMTP (RFC 5321) server implementation with per-source, per-destination delivery and filtering support
    • Experimental local storage backend & IMAP index based on relational DB
    • Sender authentication methods for inbound messages: DKIM, DMARC, SPF
    • Remote server authentication methods for outbound messages: MTA-STS, DANE, DNSSEC-aware resolver, STARTTLS Everywhere rule-set support
    • PAM-based user authentication (not used by default)

    In the end, it is not very flexible in some corners at the moment but if you just want a generic mail server set-up, it will not be a big trouble.

    Known issues

    • IMAP sequence numbers are not properly synchronized, making concurrent mailbox access potentially unsafe, though the chance of actual data damage is pretty small. See issue #188 for details.
    • Support for IP literals in e-mail addresses is disabled. Attempt to use them will result in a delivery error.

    Build artifacts

    | Artifact | SHA-256 | | --- | ----------- | | maddy executable (Linux, x86_64, musl) | bfcb649ca9586f190d30933174d4b5770f1b75f541c13c94d5458cb7578f9073 | | maddyctl executable (Linux, x86_64, musl) | 8e97306825cd0d1e0b2e5867327640a1dbfa6590e1451d2a9e7ebfc932fe53d2 | | Full Zstd tarball (Linux, x86_64, musl) | 51cc45067a99d3cfb04d72bdfde5f99e2a699b04d495f85f68b1a2894e0b41d1 |

    :lock: Attached tarballs are signed using PGP key 3197 BBD9 5137 E682 A597 17B4 34BB 2007 0813 96F4

    Note: Provided binaries do not include support for PAM authentication as it depends on system libraries in ways that are problematic to make portable. For system account authentication, you can use shadow module that reads /etc/shadow directly or maddy-pam-helper (install it into /usr/local/lib/maddy).

    Attached tarballs include complete root prefix for Linux so you can just extract contents into the root directory to install maddy if you do not want to build it from source for whatever reason.

    Build environment information:

    • Distribution: Alpine Linux 3.11.3
    • GCC: 9.1.0
    • Go: 1.13.4
    • musl-libc: 1.1.24

    Utilities and all binaries used to build the tarball can be found here: https://foxcpp.dev/maddy-repro/. In theory it should be possible to recreate the exactly same build output using them.

    Source code(tar.gz)
    Source code(zip)
    SHA256SUMS(117 bytes)
    maddy-v0.1.0.r0.g126dbdd-x86_64-linux-musl.tar.zst(24.30 MB)
    maddy-v0.1.0.r0.g126dbdd-x86_64-linux-musl.tar.zst.asc(228 bytes)
Owner
Max Mazurov
Main developer and sole maintainer of maddy mail server. Co-maintainer of numerous Go email libraries.
Max Mazurov
Mail-alias-resolve-ldap - Resolve mail alias addresses in LDAP

alias-resolve-ldap alias-resolve-ldap was written to be used as a hook for the c

Björn Busse 1 Jan 30, 2022
Filtering spam in mail server, protecting both client privacy and server algorithm

HE Spamfilter SNUCSE 2021 "Intelligent Computing System Design Project" Hyesun Kwak Myeonghwan Ahn Dongwon Lee abstract Naïve Bayesian spam filtering

Myeonghwan Ahn 1 Mar 23, 2022
:envelope: A streaming Go library for the Internet Message Format and mail messages

go-message A Go library for the Internet Message Format. It implements: RFC 5322: Internet Message Format RFC 2045, RFC 2046 and RFC 2047: Multipurpos

Simon Ser 288 Dec 26, 2022
Inline styling for html mail in golang

go-premailer Inline styling for HTML mail in golang Document install go get github.com/vanng822/go-premailer/premailer Example import ( "fmt" "gith

Nguyen Van Nhu 96 Nov 30, 2022
Golang package that generates clean, responsive HTML e-mails for sending transactional mail

Hermes Hermes is the Go port of the great mailgen engine for Node.js. Check their work, it's awesome! It's a package that generates clean, responsive

Mathieu Cornic 2.6k Dec 28, 2022
Go library for sending mail with the Mailgun API.

Mailgun with Go Go library for interacting with the Mailgun API. Usage package main import ( "context" "fmt" "log" "time" "githu

Mailgun Team 626 Dec 25, 2022
MIME mail encoding and decoding package for Go

enmime enmime is a MIME encoding and decoding library for Go, focused on generating and parsing MIME encoded emails. It is being developed in tandem w

James Hillyerd 338 Nov 30, 2022
an MDA that sends a webhook on recieval of mail

an MDA that sends a webhook on recieval of mail

forlater 10 Aug 13, 2022
📧 Example of sending mail via SendGrid in Golang.

?? go-sendgrid-example Example of sending mail via SendGrid in Golang. Get it started $ make setup # Edit environment variables $ vim ./env/local.env

ducci 1 Jan 11, 2022
Mail_sender - This library is for sending emails from your mail

Mail Sender This library is for sending emails from your mail Installation mail_

null 1 Dec 30, 2021
Mcopa - A library allows for parsing an email message into a more convenient form than the net/mail provides

Mail content parsing This library allows for parsing an email message into a mor

Mr Chen 0 Jan 1, 2022
Simple tool to test SMTP mail send with various settings including TLS1.1 downgrade

smtptest Simple tool to test SMTP mail send with various settings including TLS1.1 downgrade All settings are configurable in the config.yaml file ser

Mario 1 Sep 19, 2022
Go-mail - Email service using Kafka consumer

?? The Project This project consists in a Kafka consumer that reads messages of

Gustavo Belmonte Cioccari 2 Feb 5, 2022
Send markdown files as MIME-encoded electronic mail.

Send markdown files as MIME-encoded electronic mail.

Dmitry Kotik 5 Aug 9, 2022
Sending emails using email server talking to RabbitMQ and send grid server sending emails to email ids consumed from RabbitMQ

Sending emails using email server talking to RabbitMQ and send grid server sending emails to email ids consumed from RabbitMQ

Shivanshu Raj Shrivastava 2 Oct 27, 2022
Disposable webmail server (similar to Mailinator) with built in SMTP, POP3, RESTful servers; no DB required.

Disposable webmail server (similar to Mailinator) with built in SMTP, POP3, RESTful servers; no DB required.

Inbucket 1.1k Jan 1, 2023
golang honeypot smtp server

honeygogo-smtp standalone honeypot A lightweight SMTP honeypot server written in Go, leveraging go-smtp. A stand alone version of a module from honeyg

jothflee 1 May 4, 2022
Simple SMTP Server for Testing

go-smtptester Simple SMTP Server for Testing. How it works All received mails are saved in a sync.Map with a key: From+Recipient1+Recipient2 Mails to

null 1 Nov 18, 2021
Email 2.0 server

RIGEL.Email Secure, fast and free email 2.0 server. Download latest version Linux, BSD, Mac OS X and Windows versions available. Supported fetures in

Matvey Gladkikh 0 Jan 7, 2022