---
title: "Access Control List (ACL)"
description: "An access control list (ACL) defines which users or systems are allowed to access specific resources on a network or email system."
url: "https://mailmum.io/glossary/access-control-list-acl/"
---

# Access Control List (ACL)

An access control list (ACL) is an ordered list of rules that decides who may do
what with a resource. Each rule matches on something &mdash; an IP address, an
authenticated user, a sender domain &mdash; and produces a verdict: allow, deny,
or continue to the next rule.

In email systems the term appears in three different places that are easy to
confuse: the SMTP-level rules that decide whether a connection or a message is
accepted, the mailbox-level permissions that decide who may read a shared
folder, and the packet filter on the host itself.

## How does an ACL decide?

Nearly every ACL implementation shares the same two properties, and both are
routine sources of misconfiguration:

* **Order matters.** Rules are evaluated top to bottom and the first match wins.
  A broad `permit` placed above a narrow `deny` makes the `deny` unreachable.
* **There is a default at the end.** SMTP restriction lists in Postfix end in an
  implicit `permit`; firewall chains usually end in a `DROP`. Knowing which
  default applies is the difference between a closed relay and an open one.

## What does an SMTP ACL look like?

In [Postfix](https://www.postfix.org/) the ACL is expressed as restriction
lists evaluated at each stage of the SMTP conversation. The stage matters:
rejecting at `RCPT TO` avoids generating a bounce later, which is what keeps you
from emitting [backscatter](https://mailmum.io/glossary/backscatter/).

```txt
smtpd_client_restrictions =
    permit_mynetworks
    check_client_access cidr:/etc/postfix/client_access.cidr
    reject_rbl_client zen.spamhaus.org

smtpd_recipient_restrictions =
    permit_sasl_authenticated
    permit_mynetworks
    reject_unauth_destination
```

The referenced map is the list proper:

```txt
# /etc/postfix/client_access.cidr
192.0.2.0/24     REJECT Listed on our internal blocklist
203.0.113.17     OK
```

Exim uses the word ACL directly, with named ACLs bound to each SMTP verb:

```txt
acl_smtp_rcpt = acl_check_rcpt

acl_check_rcpt:
  accept  hosts = +relay_from_hosts
  deny    hosts = /etc/exim4/blocked_hosts
          message = Access denied
  accept  domains = +local_domains
  deny    message = Relay not permitted
```

The `reject_unauth_destination` line in the Postfix example, and the trailing
`deny` in the Exim one, are what stop the server from being an open relay. Both
are the last rule for a reason.

## What about mailbox ACLs?

IMAP has its own ACL mechanism, defined in
[RFC 4314](https://www.rfc-editor.org/rfc/rfc4314), for shared and delegated
mailboxes. Here the subject is a user rather than an IP address, and the rights
are per-folder letters:

```txt
# Dovecot: dovecot-acl in a shared mailbox directory
user=anna    lrwstipekxacd
group=sales  lrwsp
authenticated lr
```

Each letter is one right &mdash; `l` lookup, `r` read, `w` write, `s` set seen
flag, `t` delete messages, `e` expunge, and so on. This is a different system
from the SMTP restrictions above, and the two do not interact: a user with full
rights on a shared mailbox still has to pass the SMTP ACL to send anything from
it.

## How do ACLs relate to blacklisting?

An SMTP ACL is the mechanism; a [blacklist](https://mailmum.io/glossary/ip-blacklisting/) is one
of the data sources it consults. The list can be local, as in the
`client_access.cidr` map above, or remote via a DNSBL lookup such as
`reject_rbl_client`.

The practical difference is failure mode. A local map is fast, is exactly what
you put in it, and goes stale unless something maintains it. A DNSBL is
maintained for you but adds a DNS lookup to every connection, and if the
provider disappears or starts returning wildcard answers, an ACL that trusts it
can start rejecting everything.

## What should you watch out for?

* **Whitelists that outlive their reason.** An `OK` entry added to debug a
  delivery problem in 2019 is now a permanent bypass of every check below it.
* **Overly broad `mynetworks`.** A `/16` where a `/29` was meant is the most
  common way a server becomes an open relay.
* **Rules that only run at `DATA`.** Rejecting late costs you the bandwidth of
  the whole message and, if the server accepted first, produces a bounce to a
  possibly forged sender.
* **No logging of matches.** An ACL you cannot audit is one you cannot debug;
  when mail goes missing, the first question is always which rule matched.

## Related reading

The two how-tos below are ACL work in everything but name &mdash; ordered rules
in `smtpd_recipient_restrictions`, where the first match wins:

* [Blacklisting single hosts, IP addresses, and even networks in
  Postfix](https://mailmum.io/posts/blacklisting-single-hosts-ip-addresses-and-even-networks-in-postfix/)
* [Whitelisting hosts, IP addresses, and even networks in
  Postfix](https://mailmum.io/posts/whitelisting-hosts-ip-addresses-and-even-networks-in-postfix/)

The order between them is the whole point: the allow map has to be evaluated
before the reject map, or it can never match.
