• 17 min read
  • This how-to will show you how to configure:

    • A MySQL database to store information about email accounts, aliases (per-address or per-domain) and autoresponders
    • Postfix as your mail transfer agent (MTA) for SMTP
      • amavisd-new with clamav & spamassassin for automatic virus and spam filtering
      • Ability to define virtual users (via MySQL database) mapped to a real UID/GID or system users
      • Aliases generated automatically from the MySQL database, allowing one address to forward to another or all addresses on a domain to forward to another
      • Response handling email autoresponders
      • Dovecot as the local delivery agent (LDA) delivering mail to the corresponding user's mailbox
      • Dovecot as SASL authenticator
    • Dovecot for POP3 & IMAP
      • Dovecot LDA delivering mail as any system user (better security)
      • SASL authentication based on virtual user information stored in the MySQL database

    As this may seem like a bit complex at first, below is a simple overview of how the system works once put together:

    • When a user connects to the server to retrieve mail (POP3 or IMAP), Dovecot performs the SASL authentication and then connects the user to their message inbox.
    • When a user sends mail to the server destined for another domain (outgoing SMTP), Postfix calls on Dovecot to perform SASL authentication. If it succeeds, relay access is granted and the message is sent to the external mail server.
    • When an external user sends mail to the server destined for a domain handled by Postfix (incoming SMTP), Postfix checks the system and virtual user tables to ensure that the recipient is valid. If so, then it passes through a few verifications first (valid sender, virus filter, spam filter) and if all pass then the message is delivered to the corresponding user's inbox via Dovecot LDA.

    Before starting

    Please ensure that you have followed the instructions in the getting started guide here. This tutorial may require you to rebuild RPMs as well as generate SSL certificates and assumes you have the proper environment described in that guide already setup.

    If you have not setup the database server yet, please follow the database how-to first.

    Setting up the database

    Before installing dovecot or postfix, the MySQL database which will be used to authenticate all email clients needs to be initialized. Execute this SQL snippet:

    CREATE DATABASE mailconfig;
    USE mailconfig;
    CREATE TABLE `users` (
      `userid` varchar(128) NOT NULL,
      `domain` varchar(128) NOT NULL,
      `password` varchar(255) NOT NULL,
      `home` varchar(255) NOT NULL,
      `uid` int(11) NOT NULL,
      `gid` int(11) NOT NULL,
      PRIMARY KEY  (`userid`,`domain`)
    ) DEFAULT CHARSET=utf8 COMMENT='Stores information about active email accounts';

    CREATE TABLE `aliases` (
      `source` varchar(255) NOT NULL,
      `destination` varchar(255) NOT NULL,
      PRIMARY KEY  (`source`)
    ) DEFAULT CHARSET=utf8 COMMENT='Alias one address to another';

    CREATE TABLE `domain_aliases` (
      `source` varchar(128) NOT NULL,
      `destination` varchar(128) NOT NULL,
      PRIMARY KEY  (`source`)
    ) DEFAULT CHARSET=utf8 COMMENT='Alias all addresses in one domain to another';

    GRANT SELECT ON mailconfig.users TO 'mailconfig'@'localhost' IDENTIFIED BY 'random-password';
    GRANT SELECT ON mailconfig.aliases TO 'mailconfig'@'localhost' IDENTIFIED BY 'random-password';
    GRANT SELECT ON mailconfig.domain_aliases TO 'mailconfig'@'localhost' IDENTIFIED BY 'random-password';
    FLUSH PRIVILEGES;

    Replace random-password by a long squence of random characters. The mailconfig user will only be used by scripts, so you will not need to remember this password.

    Incoming mail: Dovecot

    Grab dovecot from the repositories:

    yum install dovecot

    Dovecot is now ready to be configured. Execute the following to configure the Dovecot to allow imap/pop3 access securely with compatibility for some older clients with broken protocol support:

    cat << EOF > /etc/dovecot.conf
    protocols = imap imaps pop3 pop3s

    # Log authentication failures
    auth_verbose=yes

    # Enable me to debug authentication failures
    #auth_debug_passwords=yes
    #verbose_ssl = yes

    # Maildir storage in [HOME]/[DOMAIN]/mail/[USER]
    mail_location = maildir:%h/mail/%d/%n
    umask = 0077 # 700 permissions

    # for compatability with some older clients
    pop3_uidl_format = %08Xu%08Xv
    imap_client_workarounds = delay-newmail outlook-idle netscape-eoh
    pop3_client_workarounds = outlook-no-nuls oe-ns-eoh

    # Increases performance
    maildir_copy_with_hardlinks = yes
    # Enable SSL/TLS
    ssl_disable = no
    ssl_cert_file = /etc/pki/dovecot/certs/dovecot.pem
    ssl_key_file = /etc/pki/dovecot/private/dovecot.pem
    # disable insecure ciphers
    ssl_cipher_list = ALL:!LOW:!SSLv2
    # Force STARTTLS on non-secure protocols; users *must* have either secure auth
    # (CRAM-MD5) or SSL enabled (or both)
    disable_plaintext_auth = yes
    login_process_per_connection = yes

    # Keep username case-sensitive (otherwise delivery to local users with uppercase letters fails
    auth_username_format = %u

    auth default {
      mechanisms = plain login cram-md5
      passdb sql {
        args = /etc/dovecot-mysql.conf
      }
      # Indicate that we want to prefetch userdb information from the passdb
      userdb prefetch {
      }
      # The userdb below is used only by deliver.
      userdb sql {
        args = /etc/dovecot-mysql.conf
      }
      # Offer SASL auth services
      socket listen {
        client {
          path = /var/run/dovecot/auth-client
          mode = 0660
          user = dovecot
          group  = mail # Postfix running as this user
        }
        master {
          path = /var/run/dovecot/auth-master
          mode = 0660
          user = dovecot
          group = mail # User running deliver
        }
      }
    }
    protocol lda {
      postmaster_address = postmaster@yourdomain.com
      auth_socket_path = /var/run/dovecot/auth-master
    }
    EOF

    Once again, substitute yourdomain.com and the SSL certification/key file locations accordingly. You'll notice we reference the non-existent file /etc/dovecot-mysql.conf in this configuration. Let's create that now so Dovecot has access to the MySQL database:

    cat << EOF > /etc/dovecot-mysql.conf
    # Substitutions: %u = user@domain.com, %n = user, %d = domain.com, L prefix=lowercase
    driver = mysql
    connect = host=/var/lib/mysql/mysql.sock dbname=mailconfig user=mailconfig password=random-password

    # Password lookups with support for user information prefetching:
    password_query = SELECT concat(userid, '@', domain) AS user, password, home AS userdb_home, uid AS userdb_uid, gid AS userdb_gid  FROM users  WHERE userid = '%Ln' AND domain = '%Ld'

    # For deliver user info lookups:
    user_query = SELECT home, uid, gid  FROM users  WHERE userid = '%Ln' AND domain = '%Ld'
    EOF
    chmod 600 /etc/dovecot-mysql.conf

    This creates dovecot's MySQL configuration, /etc/dovecot-mysql.conf and sets the correct permissions accordingly so that users can't go snooping for the MySQL credentials. Again, replace random-password with the correct password.

    Because the 'deliver' (Dovecot local delivery agent) executable run by Postfix has to deliver mail to different system users, it will need a setuid bit set so that Postfix can run deliver with root privileges, have it change to the appropriate user and then deliver mail to that user's inbox. We can do this easily with two commands:

    chown root.mail /usr/libexec/dovecot/deliver
    chmod 4750 /usr/libexec/dovecot/deliver

    Notice that because the last permission bit is "0", nobody except root or users in the mail group will be able to execute deliver, reducing the security risk introduced by using enabling setuid bit.

    Lastly, Dovecot needs to be started and exceptions need to be added to the firewall:

    chkconfig dovecot on
    service dovecot start
    iptables -I RH-Firewall-1-INPUT 4 -m state --state NEW -m tcp -p tcp --dport 110 -j ACCEPT
    iptables -I RH-Firewall-1-INPUT 4 -m state --state NEW -m tcp -p tcp --dport 143 -j ACCEPT
    iptables -I RH-Firewall-1-INPUT 4 -m state --state NEW -m tcp -p tcp --dport 993 -j ACCEPT
    iptables -I RH-Firewall-1-INPUT 4 -m state --state NEW -m tcp -p tcp --dport 995 -j ACCEPT
    service iptables save

    Outgoing mail: Postfix

    Normally we could just install Postfix directly from the repository, however the stock CentOS postfix is provided without MySQL support. We can easily enable this support by rebuilding the RPM:

    su - normaluser
    yumdownloader --source postfix
    rpm -i postfix*src*.rpm
    cd rpmbuild/SPECS
    sed -i.nomysql 's/%define MYSQL 0/%define MYSQL 1/' postfix.spec
    rpmbuild -ba postfix.spec

    Then install the generated Postfix RPM (rpm -Uhv ~/rpmbuild/RPMS/[arch]/postfix-[version].[arch].rpm)

    Next, we will configure Postfix to accept/relay mail:

    cat << EOF > /etc/postfix/main.cf
    #
    # Basic settings
    #

    # Domain/hostname information
    mydomain = yourdomain.com
    myhostname = mail.yourdomain.com

    # Domains that Postfix will use to deliver mail to system users
    mydestination = \$myhostname, localhost.\$mydomain, localhost

    # Trusted networks that are always granted relay access
    # You may remove 192.168.122.0/24 if you are not going to use virtual machines
    # with libvirt (default/user networking).
    mynetworks = 127.0.0.0/8, 192.168.122.0/24

    # Listen on these IP addresses
    inet_interfaces = all

    # Enter an IP address here and uncomment to get lots of info logged when
    # connecting as a client from that IP address.
    # debug_peer_list = your.ip.address.here

    #
    # File/folder locations
    #
    command_directory = /usr/sbin
    config_directory = /etc/postfix
    daemon_directory = /usr/libexec/postfix
    html_directory = no
    manpage_directory = /usr/share/man
    sample_directory = /usr/share/doc/postfix-2.3.3/samples
    queue_directory = /var/spool/postfix
    readme_directory = /usr/share/doc/postfix-2.3.3/README_FILES

    mailq_path = /usr/bin/mailq.postfix
    newaliases_path = /usr/bin/newaliases.postfix
    sendmail_path = /usr/sbin/sendmail.postfix

    #
    # Security & limits
    #
    mail_owner = postfix
    setgid_group = postdrop
    header_size_limit = 51200

    # 30MB message size limit
    message_size_limit = 31457280
    # Must have 5*30MB free in order to accept mail
    queue_minfree = 157286400

    #
    # Dovecot LDA & virtual users configuration
    #
    dovecot_destination_recipient_limit = 1
    virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
    virtual_alias_domains = mysql:/etc/postfix/mysql-virtual-alias-domains.cf
    virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
    virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
    virtual_transport = dovecot

    #
    # Other settings in alphabetical order
    #
    alias_maps = hash:/etc/aliases
    broken_sasl_auth_clients = yes
    parent_domain_matches_subdomains = no
    recipient_delimiter = +
    smtpd_banner = \$myhostname ESMTP \$mail_name: Unauthorized use of this server, for spam, bulk mail or other purposes, is not permitted.
    smtpd_client_connection_count_limit = 20
    smtpd_client_connection_rate_limit = 60
    smtpd_delay_reject = yes
    smtpd_helo_required = yes
    smtpd_helo_restrictions = permit_mynetworks, warn_if_reject, reject_non_fqdn_helo_hostname, reject_invalid_hostname
    smtpd_recipient_limit = 100
    smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination
    smtpd_sasl_auth_enable = yes
    smtpd_sasl_path = /var/run/dovecot/auth-client
    smtpd_sasl_security_options = noanonymous
    smtpd_sasl_type = dovecot
    smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_sender, reject_unknown_sender_domain
    smtpd_tls_auth_only = no
    smtpd_tls_cert_file = /etc/pki/tls/certs/yourdomain.com.pem
    smtpd_tls_key_file = /etc/pki/tls/private/yourdomain.com.key
    smtpd_tls_loglevel = 1
    smtpd_tls_security_level = may
    smtpd_tls_session_cache_database = btree:/var/spool/postfix/smtpd_tls_cache
    smtpd_tls_session_cache_timeout = 3600s
    tls_random_source = dev:/dev/urandom
    unknown_local_recipient_reject_code = 550
    EOF

    Be sure to substitute yourdomain.com for your actual domain name as well as set the smtpd_tls_cert_file and smtpd_tls_key_file configuration keys appropriately. You can use the cert.pem and private/localhost.key files that get autogenerated for the system, however it is recommended that you generate your own self-signed certificate so that the domain name matches (or even better, purchase validated ones). You may create a self-signed certificate and private key pair by running genkey --days 365 yourdomain.com and then following the on-screen instructions.

    The configuration above references several configuration files that do not exist yet, so we need to create them now. A description of what each file does is available in the comments.

    cat << EOF > mysql-virtual-alias-domains.cf
    # Generates a list of domain names that postfix should accept mail for, but
    # that have no real mailboxes (aliases only). See the virtual(5) manpage for
    # more information.

    # See the mysql_table(5) manpage for information on the format of this file
    # and the SQL query.

    user = mailconfig
    password = random-password
    hosts = 127.0.0.1
    dbname = mailconfig
    query = SELECT DISTINCT(source) FROM domain_aliases
    EOF

    cat << EOF > mysql-virtual-alias-maps.cf
    # This file contains the SQL query for looking up virtual aliases. See the
    # virtual(5) manpage for more information. The virtual alias maps allows you
    # to forward messages from one address or from a catch-all address to another
    # address (or optionally, a script). This file also handles the domain forwarding
    # of addresses in one domain to another.

    # Caveat: One would expect true domain forwarding to map user accounts as well
    # as any existing alias on the source domain to the destination domain.
    # For example, consider the use case of virtual user me@domain1.com and alias
    # info@domain1.com -> me@domain1.com. After mapping domain2.com to domain1.com,
    # one would expect info@domain2.com to map to info@domain1.com which in turn
    # maps to me@domain1.com, so info@domain2.com -> me@domain1.com. Implementing
    # this type of mapping is rather complex. The commented portion of the query
    # below should handle this correctly, however the performance penalties of using
    # such a query have not been considered nor tested on a large-scale production
    # server. Enable at your own risk.

    # See the mysql_table(5) manpage for information on the format of this file
    # and the SQL query.

    user = mailconfig
    password = random-password
    hosts = 127.0.0.1
    dbname = mailconfig
    query = SELECT destination FROM (
              SELECT concat(users.userid,'@',domain_aliases.source) AS source,
                     concat(users.userid,'@',domain_aliases.destination) AS destination
              FROM users,domain_aliases
              WHERE users.domain=domain_aliases.destination
              UNION
              SELECT * FROM aliases
              # This commented part is experimental. See above for details.
              #UNION
              #SELECT replace(aliases.source,
              #               concat('@', SUBSTRING_INDEX(aliases.source, '@', -1)),
              #               concat('@', domain_aliases.source)
              #              ) AS source,
              #       aliases.destination
              #FROM aliases,domain_aliases
              #WHERE aliases.source regexp concat('@',domain_aliases.destination,'$')
            ) AS alias WHERE alias.source='%s'
    EOF

    cat << EOF > mysql-virtual-mailbox-domains.cf
    # Generates a list of domain names that postfix should accept mail for, but are
    # not part of $mydomains as these domains are for virtual user mailboxes only.
    # See the virtual(5) manpage for more information.

    # Caveat: The SQL query includes the domains listed in the virtual alias map,
    # but there's no real good way to tell if a domain listed there has any real
    # mailboxes at all without making the queries very expensive. For practical
    # purposes though, it has no real effect if it's listed here or in
    # virtual_alias_domains so you can rest easy.

    # See the mysql_table(5) manpage for information on the format of this file
    # and the SQL query.

    user = mailconfig
    password = random-password
    hosts = 127.0.0.1
    dbname = mailconfig
    query = SELECT domain FROM (
              SELECT DISTINCT(domain) FROM users
              UNION
              SELECT DISTINCT(SUBSTRING_INDEX(source, '@', -1)) as domain FROM aliases
            ) virtual_mailbox_domains WHERE domain='%s';
    EOF

    cat << EOF > mysql-virtual-mailbox-maps.cf
    # Queries the list of virtual users to determine if a given user exists. See
    # the virtual(5) manpage for more information.

    # See the mysql_table(5) manpage for information on the format of this file
    # and the SQL query.

    user = mailconfig
    password = random-password
    hosts = 127.0.0.1
    dbname = mailconfig
    query = SELECT 1 FROM users WHERE concat(userid, '@', domain)='%s'
    EOF
    chmod 600 /etc/postfix/mysql-virtual-*.cf

    Postfix now needs to be configured to add support for additional ports (26, 465, 587) as well as to add support for dovecot's local delivery agent (LDA):

    cat << EOF >> /etc/postfix/master.cf
    # Users can use port 26 as an alternative to 25 if it is blocked by their ISP
    26        inet  n       -       n       -       -       smtpd
    # Message submission on port 587 and unofficial use of SMTP+SSL/TLS on port 465
    587       inet  n       -       n       -       -       smtpd
    smtps     inet  n       -       n       -       -       smtpd
      -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes
    # Dovecot LDA, ignores extensions (user+extension@domain.com --> user@domain.com)
    dovecot   unix  -       n       n       -       -       pipe
      flags=DRhu user=mail:mail argv=/usr/libexec/dovecot/deliver -f \${sender} -d \${user}@\${nexthop}
    EOF

    Finally, add the firewall port exceptions and start postfix:

    chkconfig postfix on
    service postfix start
    iptables -I RH-Firewall-1-INPUT 4 -m state --state NEW -m tcp -p tcp --dport 25 -j ACCEPT
    iptables -I RH-Firewall-1-INPUT 4 -m state --state NEW -m tcp -p tcp --dport 26 -j ACCEPT
    iptables -I RH-Firewall-1-INPUT 4 -m state --state NEW -m tcp -p tcp --dport 465 -j ACCEPT
    iptables -I RH-Firewall-1-INPUT 4 -m state --state NEW -m tcp -p tcp --dport 587 -j ACCEPT
    service iptables save

    Spam and virus filtering: amavisd-new

    First, install amavisd-new and some dependencies:

    yum install amavisd-new spamassassin clamd

    In the /etc/amavisd/amavisd.conf configuration file, the following items need to be changed:

    • Set $max_servers to 15
    • Set $mydomain to 'mail.yourdomain.com'
    • Set $virus_admin, $mailfrom_notify_admin, $mailfrom_notify_recip, and $mailfrom_notify_spamadmin each to "postmaster\@$mydomain"
    • Set $final_banned_destiny to D_DISCARD
    • Set $final_bad_header_destiny to D_DISCARD

    If you wish to send spam to a certain user (ie spam@yourdomain.com) instead of just discarding it, you may also set the $spam_quarantine_to and $bad_header_quarantine_to options.

    Next, Postfix needs to be configured so that it makes use of amavisd's spam/virus filtering:

    cat << EOF >> /etc/postfix/main.cf
    #
    # amavisd
    #
    content_filter = smtp:[127.0.0.1]:10024
    default_process_limit = 15
    EOF
    cat << EOF >> /etc/postfix/master.cf
    # Spam filtering
    127.0.0.1:10025 inet n - - - 0 smtpd -o content_filter= -o smtpd_sasl_auth_enable=no
    EOF

    Unfortunately, the default clamd configuration for amavisd contains some errors, preventing the amavisd.clamd service from starting correctly. We need to overwrite it with this configuration:

    cat << EOF > /etc/clamd.d/amavisd.conf
    # Use system logger.
    LogSyslog yes

    # Specify the type of syslog messages - please refer to 'man syslog'
    # for facility names.
    LogFacility LOG_MAIL

    # This option allows you to save a process identifier of the listening
    # daemon (main thread).
    PidFile /var/run/amavisd/clamd.pid

    # Remove stale socket after unclean shutdown.
    # Default: disabled
    FixStaleSocket yes

    # Run as a selected user (clamd must be started by root).
    User amavis

    # Path to a local socket file the daemon will listen on.
    LocalSocket /var/spool/amavisd/clamd.sock
    EOF

    Now it is time to enable and start the services.

    chkconfig clamd.amavisd on
    service clamd.amavisd start
    chkconfig amavisd on
    service amavisd start
    service postfix reload

    Response mail autoresponder

    Unfortunately, no CentOS 5 RPM package is currently available for the response daemon. I have attached the SRPM to this page which you can download and rebuild:

    yum install python26 python26-{devel,sqlalchemy,distribute} python-sphinx
    su - regularuser
    wget http://www.firewing1.com/sites/default/files/response-0.8-1.src_.rpm
    rpmbuild --rebuild response-0.8-1.src.rpm
    wget http://www.firewing1.com/sites/default/files/MySQL-python26-1.2.3-1.src_.rpm
    rpmbuild --rebuild MySQL-python26-1.2.3-1.src.rpm

    Note that we are also rebuilding MySQL-python26, a dependency of response. Simply install the resulting two RPMs after the builds finish.

    Before configuring Postfix, we need to create the MySQL tables that will be used to keep information about the autoresponders as well as which users have already been sent an autoresponse within a 24-hour period:

    USE mailconfig;
    CREATE TABLE `autoresponse_record` (
      `id` int(11) NOT NULL auto_increment,
      `sender_id` int(11) NOT NULL,
      `recipient` varchar(255) NOT NULL,
      `hit` datetime NOT NULL default '0000-00-00 00:00:00',
      `sent` datetime NOT NULL default '0000-00-00 00:00:00',
      PRIMARY KEY  (`id`),
      UNIQUE KEY `sender_id` (`sender_id`,`recipient`),
      CONSTRAINT `autoresponse_sender_refs` FOREIGN KEY (`sender_id`) REFERENCES `autoresponse_config` (`id`) ON DELETE CASCADE
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='Response - Autoresponse Notification Records';

    CREATE TABLE `autoresponse_config` (
      `id` int(11) NOT NULL auto_increment,
      `address` varchar(255) NOT NULL,
      `enabled` tinyint(1) NOT NULL,
      `changed` datetime NOT NULL,
      `expires` datetime NOT NULL,
      `subject` varchar(255) NOT NULL,
      `message` longtext NOT NULL,
      PRIMARY KEY  (`id`),
      UNIQUE KEY `address` (`address`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='Response - Autoresponse Configurations';
    GRANT SELECT ON mailconfig.autoresponse_config TO 'mailresponse'@'localhost' IDENTIFIED BY 'random-password2';
    GRANT SELECT,INSERT,UPDATE ON mailconfig.autoresponse_config TO 'mailresponse'@'localhost' IDENTIFIED BY 'random-password2';
    GRANT SELECT,INSERT,UPDATE ON mailconfig.autoresponse_record TO 'mailresponse'@'localhost' IDENTIFIED BY 'random-password2';
    FLUSH PRIVILEGES;
    exit;

    Similar to before, replace random-password2 with a long and complicated password. You'll never have to remember it, it is simply used internally by the response daemon.

    In the next file, you'll notice we use port 10026 because ports 10024 and 10025 have already been taken by amavisd-new.

    cat << EOF > /etc/postfix/transport_map_response
    response.internal   response:[127.0.0.1]:10026
    EOF
    postmap /etc/postfix/transport_map_response

    Now we need to inform postfix about the transport map and add the bcc mapping that will forward appropriate messages to the response-lmtpd daemon:

    cat << EOF > /etc/postfix/mysql-virtual-autoresponses.cf
    # This file controls the bcc map so that users with an autoresponder enabled  
    # have messages sent through the response transport in addition to their
    # normal transport.
    user = mailresponse
    password = random-password2
    hosts = 127.0.0.1
    dbname = mailconfig
    query = SELECT '%u#%d@response.internal' FROM autoresponse_config WHERE address = '%s' AND enabled=1
    EOF
    chmod 600 /etc/postfix/mysql-virtual-autoresponses.cf
    cat << EOF >> /etc/postfix/main.cf
    #
    # Response autoresponder
    #
    response_destination_recipient_limit = 1
    transport_maps = hash:/etc/postfix/transport_map_response
    recipient_bcc_maps = proxy:mysql:/etc/postfix/mysql-virtual-autoresponses.cf
    proxy_read_maps = \$local_recipient_maps \$mydestination \$virtual_alias_maps \$virtual_alias_domains \$virtual_mailbox_maps \$virtual_mailbox_domains \$relay_recipient_maps \$relay_domains \$canonical_maps \$sender_canonical_maps \$recipient_canonical_maps \$relocated_maps \$transport_maps \$mynetworks \$recipient_bcc_maps
    EOF
    cat << EOF >> /etc/postfix/master.cf
    # Response autoresponder
    response  unix  -       -       n       -       4       lmtp -o disable_dns_lookups=yes
    EOF
    service postfix reload

    Of course, you'll need to replace random-password2 in /etc/postfix/mysql-virtual-autoresponses.cf with the random password created earlier for the mailresponse user.

    That's it! You can now add a row in the mailconfig.autoresponse_config table to have response-lmtpd automatically reply to any message sent to that user.

    Resources and further reading