Post

Sendmail and 'partly-there' domains

Just recently I had to set up a sendmail server for an office with 7 local users and more roaming users. The current setup had all users checking email via POP3 to the ISP. This is an issue as email sent locally within the office passed over the ADSL connection twice. Sendmail however is quite difficult to work with when it can’t handle the entire domain. As not all users on the domain have an account on the office server, email would bounce back as user unknown - even though a POP3 account existed with the ISP.

I’ll write up a dummy scenario to make this clearer.

  • local1 - Checks email on the local server via IMAP. Server downloads email via fetchmail and throws it in the users IMAP mailstore.
  • local2 - Same configuration as local1.
  • remote1 - This user doesn’t have an account on the local server but gets email via the ISPs POP3 mail account.

All users have the same domain name in their email address. For this example, we’ll use mydomain.com.au.

The issue starts with a couple of common problems.

a) If we put mydomain.com.au in /etc/mail/local-host-names, then email between local1 and local2 will be handled locally - which is great. The problem though is that mail between local1 and remote1 will bounce with a ‘user unknown’ error.

b) Having a smarthost defined to send email out via the ISPs mail server will also mean that mail between local1 and local2 will also go to the smarthost - essentially uploading it to be downloaded again. This adds delay and also slows things down.

To fix this, we can use the virtusertable to rewrite the addresses of the email addresses - but by default, sendmail does not run the virtusertable on any addresses of domains it does not own.

We can however modify our sendmail.mc with the following code to tell sendmail to run domains we specify through the virtusertable! The code is as follows:

1
2
3
FEATURE(`virtusertable', `hash -o /etc/mail/virtusertable.db')dnl
LOCAL_CONFIG
F{VirtHost}/etc/mail/virtual-domains

Now we can add the domains we want to run the virtusertable on in /etc/mail/virtual-domains: mydomain.com.au

The final step in this solution is to then specify what users we want to rewrite to be local users. This is in /etc/mail/virtusertable:

1
2
local1@mydomain.com.au     local1@localhost
local2@mydomain.com.au     local2@localhost

Now when we test these addresses using sendmail -bt from the server, we see the address translation happen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> /parse local1@mydomain.com.au
Cracked address = $g
Parsing envelope recipient address
canonify           input: local1 @ mydomain . com . au
Canonify2          input: local1 < @ mydomain . com . au >
Canonify2        returns: local1 < @ mydomain . com . au . >
canonify         returns: local1 < @ mydomain . com . au . >
parse              input: local1 < @ mydomain . com . au . >
Parse0             input: local1 < @ mydomain . com . au . >
Parse0           returns: local1 < @ mydomain . com . au . >
ParseLocal         input: local1 < @ mydomain . com . au . >
ParseLocal       returns: local1 < @ mydomain . com . au . >
Parse1             input: local1 < @ mydomain . com . au . >
Recurse            input: local1 @ localhost
canonify           input: local1 @ localhost
Canonify2          input: local1 < @ localhost >
Canonify2        returns: local1 < @ intranet . mydomain . com . au . >
canonify         returns: local1 < @ intranet . mydomain . com . au . >
parse              input: local1 < @ intranet . mydomain . com . au . >
Parse0             input: local1 < @ intranet . mydomain . com . au . >
Parse0           returns: local1 < @ intranet . mydomain . com . au . >
ParseLocal         input: local1 < @ intranet . mydomain . com . au . >
ParseLocal       returns: local1 < @ intranet . mydomain . com . au . >
Parse1             input: local1 < @ intranet . mydomain . com . au . >
Parse1           returns: $# local $: local1
parse            returns: $# local $: local1
Recurse          returns: $# local $: local1
Parse1           returns: $# local $: local1
parse            returns: $# local $: local1
2                  input: local1
2                returns: local1
EnvToL             input: local1
EnvToL           returns: local1
final              input: local1
final            returns: local1
mailer local, user local1

Checking against any other email address should show the normal delivery method - either normal MX lookup and delivery, or via a defined smarthost.

This post is licensed under CC BY 4.0 by the author.