# DirectAdmin mail delivery problems: forwarder loops, send-limit counting and outbound MX lookups

Source: https://srvscripts.com/guides/directadmin-mail-delivery-problems/
Updated: 2026-10-03
Publisher: srvScripts (https://srvscripts.com/)

Most DirectAdmin mail complaints reduce to three mechanisms: a forwarder that sends mail back to where it came from, a user hitting the daily send limit without knowing what counts against it, and mail for a locally hosted domain that is supposed to be delivered elsewhere. Each one leaves a distinct trace in `/var/log/exim/mainlog`, and each has a configuration knob that changed in the 1.69x and 1.70x releases. This guide takes them in turn.

In short: Forwarder loops show as one message ID delivered dozens of times in /var/log/exim/mainlog and are stopped by the loop protection in the 1.693+ Exim configuration plus removing the return leg; send limits count every recipient and every…

**Short answer:** Forwarder loops show as one message ID delivered dozens of times in `/var/log/exim/mainlog` and are stopped by the loop protection in the 1.693+ Exim configuration plus removing the return leg; send limits count every recipient and every forwarded message against `/etc/virtual/limit`, so check `/etc/virtual/user_usage/USER` before raising it. Mail for hosted domains whose mailboxes live elsewhere is routed out by `FORCED_MX_DNS_CHECK` (1.703+) or by unticking the local mail server option per domain.

## Forwarder loops

A loop forms when `sales@example.com` forwards to `team@partner.example` and that address, or a rule at the recipient, forwards back. Before 1.693 Exim would deliver the message repeatedly until the hop count in the headers hit the limit, generating a bounce for every copy and often triggering a send-limit breach for the account. 1.693 added loop detection to the forwarder handling: DirectAdmin’s Exim configuration now tracks the forwarding path and stops a message that returns to an address it has already visited.

The symptom in the log is a line ending with the loop-protection reason, or, on unpatched configurations, a rapid sequence of deliveries for one message ID. Find them by counting deliveries per message:

```
grep '=>' /var/log/exim/mainlog | awk '{print $3}' | sort | uniq -c | sort -rn | head
```

A message ID with dozens of deliveries is a loop. Identify the forwarder from `/etc/virtual/example.com/aliases` and either remove the return leg or replace the forward with a copy-and-keep configuration on the user’s forwarders page, which prevents the round trip.

Confirm the server has the protection by checking the Exim configuration version:

```
grep -m1 'exim.conf' /etc/exim.conf | head -1
da build exim_conf
```

Rebuilding `exim.conf` through CustomBuild pulls the current configuration set, which includes the loop check.

## Send-limit counting

Each user has a daily outbound limit set by the package and stored in `/etc/virtual/limit` (the default) or `/etc/virtual/limit_USER` for an override. The count is kept per user in `/etc/virtual/user_usage/USER` and reset by the nightly cron. What surprises administrators is what increments it: every recipient counts, not every message, and forwarded mail counts against the account that owns the forwarder. A newsletter to two hundred addresses uses two hundred of the limit; a forwarder that receives a hundred messages a day and passes them on uses a hundred more.

When the limit is hit, Exim rejects further submissions with a message naming the limit, and the log shows the `check_limits` result. Inspect and, if justified, raise for one user:

```
cat /etc/virtual/limit
cat /etc/virtual/user_usage/USER
echo 2000 > /etc/virtual/limit_USER
```

A user who hits the limit unexpectedly is often compromised. Before raising anything, count the recipients per sender in the log for the day and look at the subject lines; our [find the source of outgoing spam](/guides/find-source-of-outgoing-spam-cpanel/) guide describes the same investigation and the Exim queries carry over almost unchanged.

Note that DirectAdmin 1.702 and later configurations no longer use the `${perl{check_limits}}` condition in custom routers. If you added a smarthost router by hand in `/etc/exim.routers.pre.conf` following an older recipe, remove that condition or the router silently never matches.

## Outbound MX lookups for local domains

A domain hosted on the server for web but with mail at a third party is a classic misdelivery source. Exim treats any domain listed in `/etc/virtual/domains` as local and delivers to the local mailbox, so mail from one hosted site to another hosted domain that actually uses an external provider never leaves the server.

1.703 introduced `FORCED_MX_DNS_CHECK`. When enabled, Exim looks up the MX for a local domain before delivering locally and, if the MX points elsewhere, routes the message out over SMTP. This removes the need to manually untick local delivery per domain, at the cost of a DNS lookup per local delivery. It is set as an Exim macro in the custom variables file:

```
grep FORCED_MX_DNS_CHECK /etc/exim.variables.conf.custom
echo 'FORCED_MX_DNS_CHECK=1' >> /etc/exim.variables.conf.custom
da build exim_conf
```

The per-domain method still works and is the right choice when only a few domains are external: the user unticks **Local mail server** on the MX records page, which moves the domain from `/etc/virtual/domains` into the remote list. [External mail with Google Workspace or Microsoft 365 on DirectAdmin](/guides/directadmin-external-mail-workspace-m365/) covers that path and its DNS.

## Common pitfall: the MX check with a broken resolver

With `FORCED_MX_DNS_CHECK` enabled, a resolver outage does not just slow mail; it makes Exim treat every local domain as local because the lookup fails, and mail for external-hosted domains lands in local mailboxes until DNS recovers. If the server runs a local Unbound resolver, make sure `resolv.conf` has a fallback entry, and watch for `MX lookup` errors in the mainlog after any resolver change.

## Verify

Send a test from a hosted account to an address at an externally hosted local domain and follow the message:

```
exim -bt user@external-hosted.example
tail -f /var/log/exim/mainlog
```

`exim -bt` prints the router and transport Exim would use; with the MX check working it shows the remote SMTP transport and the external MX host. For the send limit, confirm the usage file resets after midnight and that the user’s counter rises by recipient count on a multi-recipient test. For loops, resend through the forwarder and confirm exactly one delivery per message ID in the log. Our [Exim mail queue report](/scripts/exim-mail-queue-report/) run hourly highlights the queue growth that all three faults produce before users report them.

## DirectAdmin mail delivery problems at a glance

**Official documentation:** [DirectAdmin documentation](https://docs.directadmin.com/), [RFC 5321 (SMTP)](https://www.rfc-editor.org/rfc/rfc5321), [Linux man pages](https://man7.org/linux/man-pages/).

**Related guides:** [Choosing a VPS for a cPanel or DirectAdmin server in 2026](https://srvscripts.com/guides/best-vps-for-cpanel-directadmin-server/) · [Exim 4.99/4.100 on cPanel and DirectAdmin: the 2026 security fixes and what changed for admins](https://srvscripts.com/guides/exim-4-100-security-fixes/) · [Warm up a new mail server IP or sending domain without landing in spam](https://srvscripts.com/guides/warm-up-new-mail-server-ip-domain/).

## Frequently asked questions

### Does the DirectAdmin send limit count forwarded mail against the user?

Yes. Every recipient of every message that passes through the account counts, including messages a forwarder relays on, so a busy forwarder can exhaust a low limit without the user sending anything themselves.

### How long does it take for the send-limit counter to reset?

The counter in `/etc/virtual/user_usage/USER` is reset by the nightly DirectAdmin cron, so a user who hits the limit is blocked until the following day unless an administrator raises the limit or clears the file.

### Can I undo this?

Yes. A raised per-user limit is reversed by deleting `/etc/virtual/limit_USER`, and `FORCED_MX_DNS_CHECK` is disabled by setting it to `0` in `/etc/exim.variables.conf.custom` and rebuilding `exim.conf` with `da build exim_conf`.
