MSA MYSTREAM AGENCY

How to Block Email from a Specific IP Address in EXIM (With Custom Messages, Dynamic Filters, and Logging)

If you're running your own mail server with EXIM, chances are you'll want fine-grained control over who can send mail to your domain. One of the most effective measures is blocking specific IP addresses—whether for abuse, spam, or internal policy.

In this guide, we'll cover:

  • How to block a specific IP address in EXIM
  • Where to apply the rule in the config
  • How to set a static or dynamic rejection message
  • Best practices for blacklist management (static and dynamic)
  • How to log rejections for monitoring and abuse tracking
  • Advanced ideas like combining blocks with DNSBLs, rate limits, and geofencing

1. Where to Block IPs in EXIM

EXIM's configuration is modular, and IP-based blocking is best handled in the Access Control Lists (ACLs). The main file to edit is usually:

/etc/exim4/exim4.conf.template

Or, if using split configuration:

/etc/exim4/conf.d/acl/40_exim4-config_check_rcpt

You'll want to place your block rule in the acl_check_rcpt section, which is evaluated when a client issues the RCPT TO: command.

2. Blocking a Specific IP with a Static Message

Here's a simple example to block 123.123.123.123:

deny
    message = Your message has been rejected because the sender is blacklisted.
    condition = ${if eq{$sender_host_address}{123.123.123.123}{yes}{no}}

Explanation:

deny stops message delivery.

message defines what the sender will see.

condition checks the sender's IP and returns yes to trigger the block.

Place this block early in acl_check_rcpt to act fast and reduce resource usage.

3. Using Dynamic Rejection Messages

Sometimes, a static message isn't enough. A dynamic message can help:

  • Identify why an IP is blocked (e.g. RBL, country block, temporary ban).
  • Include timestamps or internal references for traceability.
  • Assist legitimate users in appealing a block with context.

Example:

deny
    message = Message blocked. IP: $sender_host_address is on our internal blacklist. Ref: ${sg{${lookup{$sender_host_address}lsearch{/etc/exim4/blacklist.txt}}}{ }{}}.
    condition = ${if exists{/etc/exim4/blacklist.txt}{${if match{$sender_host_address}{${lookup{$sender_host_address}lsearch{/etc/exim4/blacklist.txt}}}{yes}{no}}}{no}}

This loads the reason from a file dynamically and shows it in the rejection.

4. Managing Blacklists (Static and Dynamic)

Static Blacklist:

Maintain a file like:

/etc/exim4/blacklist.txt

With entries such as:

123.123.123.123 : Spammer
111.111.111.111 : Internal Abuse

Then use lsearch to look up IPs.

Dynamic Blacklist:

You can build a script that:

  • Watches EXIM logs for abuse
  • Adds IPs to the blacklist temporarily (e.g. for 24 hours)
  • Syncs with fail2ban or other security tools

Use cron, systemd timers, or even inotify for auto-updates.

5. Logging and Reporting Rejection Hits

To monitor blocks without flooding your logs, pipe hits to a lightweight logger.

Example using add_header and log tailing:

deny
    message = Access denied.
    condition = ...
    add_header = X-Blocked-IP: $sender_host_address

Then, tail logs and extract:

grep "X-Blocked-IP" /var/log/exim4/mainlog | while read line; do
    echo "$line" | nc logger.mycompany.internal 9000
done

Or send asynchronously to an ELK stack, InfluxDB, or Loki via vector/logstash.

6. Advanced: Combine with DNSBL, Rate Limits, or Country Blocks

EXIM's flexibility allows chaining rules.

Example: Block IP if on Spamhaus AND in China (via MaxMind):

deny
    message = Blocked due to spam or geolocation policy.
    condition = ${if or{
        {def:sender_host_address}
        {match{$sender_host_address}{${lookup dnsdb{zen.spamhaus.org}{$value}{}}}}
        {match{${lookup{$sender_host_address}lsearch{/etc/exim4/geo_blacklist.txt}}}{CN}}
    }}

Conclusion

Blocking by IP in EXIM isn't limitd to writing one line at a time, manually, you can use it to improve your layered security strategy. Use static IP blocks for known bad actors, dynamic blacklists for behavioural filtering, and make your messages smart enough to help both users and your abuse team.

See also: How to sync EXIM with Fail2Ban for brute force protection, and integrating GeoIP blocking for GDPR compliance.

Email us right here