Sendmail routing through Microsoft Active Directory

Sendmail routing through Microsoft Active Directory

To give credit where credit is due, the attachment was sent to me from Randy Fox from csgsystems. There’s one bug with public folders. The workaround is to create a mailing list by the same name and make the public folder a member of the list.

If you’re reading this, you are probably running a Microsoft Exchange
Server or probably currently already have sendmail relaying to an Exchange
Server and want to improve your setup.

Most sendmail to exchange setups will take mail and blindly relay the mail
over. If yours is like this, you will know that you get email bounces that
can go nowhere because most of the initial intentions of the emails were
for spam and they would just send messages to users that they don’t know
even exist. A major problem with this is that it will hold up your sendmail
queue and hinder your performance as it will try to send these emails just
as much as the ones that are important and need to be sent out immediately.
This article will show you how to use sendmail’s ldap features to look into
the Active Directory to see where the mail should go and have sendmail send
it there. By having sendmail look into the Active Directory, it will know
whether users exist and will stop immediately after the “RCPT TO” in the
envelope if users don’t exist, eliminating the useless, bounce emails that
never get anywhere.

This procedure is not fully supported by Sun support because of the amount
of customization required.

First off, you will need a version of sendmail that has ldap capabilities
compiled into it. You can check this with:

/usr/lib/sendmail -d0.11 < /dev/null

Version 8.12.8+Sun

When you see LDAPMAP, you know that it will work. Solaris 7-9 should all
work. Patches are available for those that don’t.

The Microsoft Active Directory is a different ldap server than your typical
ldap server, so you will want to browse the directory and learn more about
how it’s designed. You will need to find or create a user that can browse
the Active Directory.

For the sake of simplicity, this example will use the Administrator userid
and his password to bind to the Active Directory server and find view its

For Solaris 8-9, if you have the SUNWlldap package installed, you can use
the ldapsearch command located /usr/bin. Run something like:

/usr/bin/ldapsearch -L -D “cn=Administrator, cn=Users, dc=domain, dc=com” \
-h -b “dc=domain,dc=com” objectclass=* \
> /tmp/active_directory.ldif

It will ask you for a password. You want to input the Windows
Administrator’s password there. You can open the /tmp/active_directory.ldif
file and read it and you can find a lot of the information in the directory

If you do not have the ldapsearch command, while logged in as Administrator
on the Exchange server, you can achieve a similar result in Windows with

ldifde -f c:\temp\export.ldif -v

Upon knowing what’s in the Active Directory, you can proceed to plug this
data into your sendmail configuration.

Because the Active Directory is a little different from your standard ldap
server, some hacks are required to make sendmail work.

You want to go into your /usr/lib/mail/hack directory. You can create it if
the directory isn’t there. (The files are attached.) In there, you want to create a file called
AD_ldap_routing.m4 and inside of it have:

# Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
# All rights reserved.
# By using this file, you agree to the terms and conditions set
# forth in the LICENSE file which can be found at the top level of
# the sendmail distribution.

VERSIONID(`$Id: ldap_routing.m4,v 8.8 2001/06/27 21:46:31 gshapiro Exp $')

# Check first two arguments. If they aren't set, may need to warn in proto.m4
ifelse(len(X`'_ARG1_), `1', `define(`_LDAP_ROUTING_WARN_', `yes')')
ifelse(len(X`'_ARG2_), `1', `define(`_LDAP_ROUTING_WARN_', `yes')')

# Check for third argument to indicate how to deal with non-existant
# LDAP records
ifelse(len(X`'_ARG3_), `1', `define(`_LDAP_ROUTING_', `_PASS_THROUGH_')',
 _ARG3_, `passthru', `define(`_LDAP_ROUTING_', `_PASS_THROUGH_')',
 `define(`_LDAP_ROUTING_', `_MUST_EXIST_')')

# Check for fouth argument to indicate how to deal with +detail info
ifelse(len(X`'_ARG4_), `1', `',
 _ARG4_, `strip', `define(`_LDAP_ROUTE_DETAIL_', `_STRIP_')',
 _ARG4_, `preserve', `define(`_LDAP_ROUTE_DETAIL_', `_PRESERVE_')')

# LDAP routing maps
Kldapmh ifelse(len(X`'_ARG1_), `1',
 `ldap -1 -v msExchHomeServerName,msExchExpansionServerName -k (|(mail=%0)(proxyaddresses=smtp:%0))',

Kldapmra ifelse(len(X`'_ARG2_), `1',
 `ldap -1 -v targetAddress -k (|(mail=%0)(proxyaddresses=smtp:%0))',

The next step is to make the modifications to your .mc file.

The first feature we should add is a mailertable to tell sendmail where to
send mail with different ldapsearch results.

So we add the line:

To add the ldap features into sendmail. Add the lines (of course, you put
in your domains):
LDAPROUTE_DOMAIN(`')dnl # what domain to do ldap lookups for.
LDAPROUTE_DOMAIN(`')dnl # alternate domain to do ldap lookups for.

You then need to specify your Active Directory settings (this all fits on
one line). You will also need to create the file /etc/mail/ldap.passwd. (We
will do this later)

define(`confLDAP_DEFAULT_SPEC',`-h -M simple -d "cn=Administrator, cn=Users, dc=domain, dc=com" -P /etc/mail/ldap.passwd -p 389 -b "dc=domain, dc=com"')

We will now have to add some custom rulesets. There’s also one line you need to change here:

R<> </ o=CSG Systems , Inc . / ou=CSG / cn=Configuration / cn=Servers / $+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2

Make it match your organzation. You can find this by looking at your
active_directory.ldif file and seeing
the msExchHomeServerName attribute. Every user entry should have something

msExchHomeServerName: /o=Domain/ou=First Administrative Group/cn=Configuration/cn=Servers/cn=domaincontroller

With that, you just strip off the last cn= and make spaces in between.

R$* < @ $=m . > $* $#esmtp [email protected] $2 $: $1 < @ $2 . > $3 internal addr delivered to host
R$* < @ $+ . $=m . > $* $#esmtp [email protected] $2 . $3 $: $1 < @ $2 .$3 . > $4 internal w/host

# Begin custom LDAP rule set.
# the following lines are essentually copied from the proto.m4 file. They are entered here to maintain the proper,
# original flow control but process the Active Directory response properly.
# pass names that still have a host to a smarthost (if defined)
R$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name

# deal with other remote names
R$* < @$* > $* $#esmtp [email protected] $2 $: $1 < @ $2 > $3 [email protected]

# handle locally delivered names
R$=L $#local $: @ $1 special local names
R$+ $#local $: $1 regular local names

#do the LDAP lookup for the Exchange Mail Host
R<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>

# if mailRoutingAddress (targetAddress) and local or non-existant mailHost,
# return the new mailRoutingAddress
R<$+> <$=w> <$+> <$+> <$*> [email protected] $>Parse0 $>canonify $1
R<$+> <> <$+> <$+> <$*> [email protected] $>Parse0 $>canonify $1

# fix hostname in Mailertable, relay from there
R<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1

# if no mailRoutingAddress and local mailHost,
# return original address
R<> <$=w> <$+> <$+> <$*> [email protected] $2

# if no mailRoutingAddress and non-local mailHost,
# relay to mailHost (Exchange Server) with original address
# "de-AD" response at same time
# You'll need to do the query manually the find the proper stuff to pull out
R<> </ o=CSG Systems , Inc . / ou=CSG / cn=Configuration / cn=Servers / $+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2

# if still no mailRoutingAddress and no mailHost,
# try @domain
R<> <> <$+> <$+ @ $+> <$*> [email protected] $>LDAPExpand <$1> <@ $3> <$4>

# if no mailRoutingAddress and no mailHost and this was a domain attempt,
# return the original address
R<> <> <$+> <@ $+> <$*> [email protected] $1
# End of custom LDAPExpand rule set

You now want to create your cf file.

/usr/ccs/bin/m4 ../m4/cf.m4 >

Now that we’re done with the cf file, we need to supply the other files to
the configuration.
Create the ldap.passwd file:
echo “activedirectorypassword” > /etc/mail/ldap.passwd

Create the mailertable to tell sendmail where to send the mail. When we
stripped the last cn= off of the msExchHomeServerName, we will take that
and put it here. So my /etc/mail/mailertable will look like:

After you create this file, you will need to put it in the database for
sendmail to read it. Do this by running the command:
makemap -v hash /etc/mail/mailertable < /etc/mail/mailertable

You will also need to tell sendmail that you take mail for the domain as
well, so you want to put your domain in /etc/mail/local-host-names.
echo “” > /etc/mail/local-host-names

Now we will need to restart sendmail and test it. Run a command like this
for a user in the Active Directory:
/usr/lib/sendmail -bv [email protected]

You should see: [email protected]… deliverable: mailer esmtp, host, user [email protected]

If you run the same command on a user that’s not in the Active Directory,
you should get:
/usr/lib/sendmail -bv [email protected]
[email protected]… User unknown

Once you’ve got this, you’re all set!

Some ideas on troubleshooting:

If you see
/usr/sbin/sendmail -bv [email protected]
[email protected]… deliverable: mailer relay, host cn=exchangeserver, user
[email protected]

You probably forgot the mailertable. The mailertable translates the cn=host
to the actual host and tells it which protocol to use to send the mail. In
our case, we use esmtp.

If you see something like this:
/usr/sbin/sendmail -bv [email protected]
[email protected]… deliverable: mailer esmtp, host, user
>/o=domain/ou=First.Administrative.Group/cn=Configuration/cn=Servers/[email protected]<

You have the wrong data in the area where it says:
# relay to mailHost (Exchange Server) with original address
# “de-AD” response at same time
in the file.


Because it’s hard to read the .mc file stuff in the text, you can download the files here: AD_Routing.tar

Controlling SPAM with Sendmail

It’s annoying to read. It wastes your time. It wastes you disk space. It can also be a really big problem for mail administrators, especially for those with large networks and many users to look over.

There are many solutions to battle spam, but most administrators are hesitant in the event that there is a good chance of blocking or discarding legitimate and possibly email in the process.

Hopefully this article will give you a better understanding of what is at risk and what you can do about blocking, discarding, or marking spam, increasing your mail performance, save disk space, and save time reading through them.

Well, let’s get started …

First, let’s see that you’re not part of the problem. More specifically, let’s make sure that you’re not helping the spammers by being an open relay. This just means that you don’t allow unauthorized people to relay mail through your mail server. This isn’t likely if you’re using Sendmail 8.9 or above, but if you are using custom rulesets or if you played with the file yourself, you may want to have this checked out. Let’s also check to see if you’re listed on any blacklists while you’re at it. The site I like to use to test open relays is There, you just put in your IP address and in a day, you should get the results. You can check if you’re listed on any blacklists by going to in their spam database lookup. If you are listed, you may want to contact the list owner to have yourself removed after a test or with an explanation.
Another thing you can do to protect your users and increase the performance of your system is to add to your mc file:
This will stop spammers from checking against your machine to see if a user exists, make sure that all mail that comes in starts with the MTA saying “helo,” and allow only root to run the mail queue. Disallowing the features will help increase your performance because your system will no longer respond to a bunch of useless questions.
Let’s start fighting spam!
The risk in blocking spam could be substantial. The last thing you want to do is block an important email that could have meant a lot of business. Of course, the least risky method would be not to block spam at, but what would be the point of this article?
We should see the differences the versions of Sendmail because in as you go up in version, the more you can do against spam and the easier it is.
An example of this is that in Sendmail 8.9 or higher, there’s a:
If this feature is not included in the sendmail configuration, sendmail will not accept mail from domains that do not resolve, meaning that there is no A record or MX record for that domain. This prevents spammers from coming up with fake domain names or at least limits them to only certain fake domain names.
One caveat for this is that as you probably know, some DNS servers do get poisoned or cache false information. For this reason, this can prevent you from getting legitimate email.
In Solaris, this feature is automatically turned on in DOMAIN(solaris-generic). For that reason, in the file, you may wish to replace
Changing to DOMAIN(solaris-antispam) will remove FEATURE(`accept_unqualified_senders’) from your mc file as well.

A relatively low risk method of blocking spam is by subject line. You can do this with a simple addition to the mc file before compiling it.
Details for this are here: … index_html
This would be good for blocking viruses that are going around and spam with the same subject line. The subject line here however, would have to be an exact match. Of course, spammers are smarter than this. For this reason, on a lot of spam, you will see that the subject lines have random characters at the end of them. Sendmail allows for regular expression matching as well. To do this, there is an example in the README file in /usr/lib/mail/cf. It’s available in Sendmail 8.10 or above.

The next relatively risk-free method of blocking spam is by their envelope from address. In Sendmail 8.8.8 (Solaris 2.6), it is relatively expensive and your list probably shouldn’t be very big and it is also somewhat difficult as well. You can store a list of hosts and a list of email addresses, but they get stored as a list and not a map. Your performance degrades as your list gets longer since the entire file is read and each mail will go through the list of checks as it is processed.
Details for setting this up are here:
In Sendmail 8.9 and above (Solaris 7-9), you have what is known as the access database. With this, you can keep a large list of email addresses, domains, subdomains, IP addresses, and even IP networks. Since it is stored in a map (hashed database), regardless of it’s size, Sendmail will look at a map and make one call. (It will take longer to build the map if it’s larger and while the map is being built, you won’t have one in it’s place, but that’s a different discussion.) I would advise keeping a pretty big list. I have a relatively small list of domains and no IP addresses in my list because IP addresses change ownership and there’s always that ever so slight chance that you’re blocking email from a domain that you want email from. I have a pretty big list of email addresses. Some can argue that it’s pointless because the spammers can change their email addresses each time, but I think that it’s still worth having.

To use the access database, in versions 8.9 and higher, simply add to your mc file:
FEATURE(`access_db’,`hash -o /etc/mail/access.db’)dnl
FEATURE(`access_db’,`hash -T -o /etc/mail/access.db’)dnl (in Sendmail 8.12)
Create the file: /etc/mail/access RELAY REJECT
[email protected] REJECT DISCARD
[email protected] 550 No Such User
You can use the RELAY (if you relay for the domain like being a secondary MX record), REJECT will give an access denied by default, and DISCARD will throw the message into /dev/null. You can also give your own error message and assign it a number. Different numbers are supposed to mean different things – you should follow the error codes listed in RFC 821. I like to use discard because you don’t want spammers to get any more clever in their spamming ways and one way of assuring this is by letting them think that you received the email. After you’re done building the file, you need to build the database. Do this with:
makemap hash /etc/mail/access < /etc/mail/access
You do not need to restart Sendmail for this to take effect.

Realtime Blackhole Lists are lists of either mail servers on the Internet are open-relay or known spammers. They are useful in stopping spam because they are lists that you do not have to maintain. They are on the Internet where some are free, some are not. What they do is once a connection is made to your mail server, it will do a DNS lookup on a database to see if it’s listed. If listed, it will return an error message to the client giving him a message. This message is custom, but usually will say something like you are listed on this blackhole list and go to them to get removed.

Detailed instructions on setting this up are here:

On Sendmail 8.9 or higher, it’s very simple. Add the following lines to your mc file:
FEATURE(`dnsbl’, `’)dnl
You can replace “” with any other services you will be using.
Here’s a pretty extensive list:
Be aware that not all of them are known spammers and I’m not sure if the lists are maintained by humans. Using the lists can make you lose legitimate emails. They show no mercy on incompetent email administrators who do not know how to protect their machines from sending out spam.
Another note worth mentioning is that the lists can degrade your performance as well. If you are getting too many mails from different IP addresses for instance or if you are using too many lists and your DNS server is slow, you can have problems. If the list maintainers allow you to download their zone files into your own DNS server, you best do so.

Spamassassin ( and Vipul’s Razor ( are two free and very effective spam-fighting applications. They both require you to compilation however. If you enjoy compiling software and have a spam problem, these tools are well worth the time in setting up. Being effective tools, it would make sense that they are complicated. Spamassassin will go through your mail and look thru it and see if the mail fits a bunch of tests listed here: If it fits a particular test, it will assign points to it. So if the email has “sex” in it or if its html is formatted a certain way, it will give or take points. A final value will determine whether or not the mail is spam. You have the power to customize the amount of points it assigns for each test and you also can decide on how many points an email has to have in order to be considered spam. Another nice feature of Spamassassin is that it uses the DNSBL’s. It can see that an email came from a certain IP address and rather than reject the mail outright, it will assign it points and the rest of the email can determine whether or not the email is spam. It can also incorporate Vipul’s Razor. Vipul’s Razor is a “distributed, collaborative, spam detection and filtering network.” Spamassassin can take the Razor’s score into consideration as well.
While Spamassassin and Razor are good applications, you will need to find a way for Sendmail to call these applications and use them. The easiest way I think is with Procmail ( Usage of Procmail however, limits your mail scanning however because it is not done as you are receiving the mail, but after Sendmail has already received the mail and passed onto the Mailer. This means that it would not work for domains that you relay for, only users and aliases on that machine.
Instructions for installing Spamassassin ( and Razor ( and both include the usage of Procmail. Here are some other cool things you can do with procmail:
For scanning all incoming mail, I think that MIMEDefang ( is one of the best milter applications available. It checks mail as it is being received and can decide while in transit, whether to relay, deliver, discard, or reject the email. MIMEDefang works well with various antivirus applications and works with Spamassassin. For milter capability however, you should run Sendmail version 8.12 or higher. It was available at the time that 8.11 was out, but we are advised not to use it. Sun’s 8.11.6 version of sendmail does not have milter compiled into it. Sun’s 8.12 Sendmail does, but the operating system does not include the libmilter.a file. For this, you will have to download the source (from and compile it from the libmilter directory.
If you are running Solaris 2.6, you should be running Sendmail 8.8.8. For Solaris 7 and 8, you should run 8.11.6 and for Solaris 9, you should be running 8.12.8. If not, patches are available. The way to determine the version you are running is with the command:
/usr/lib/sendmail –d0.101
If you wish to be running any other version of Sendmail, you can compile it from the source from I would like to point out that if you do, you should at least compile in the:
define(`confMAPDEF’, `-DNEWDB’)
This is for hash support in your maps (virtusertable, access_db, genericstable, etc.) You will need the BerkeleyDB ( for this.

Blocking incoming mail by subject in sendmail

LOCAL_RULESETS HSubject: $>Check_Subject
D{MMsg}This message may contain the LoveLetter virus. SCheck_Subject
R${MPat} $*$#error $: 550 ${MMsg}
RRe: ${MPat} $*$#error $: 550 ${MMsg}

In this case, we are blocking the ILOVEYOU virus.
“D{MPat}ILOVEYOU” is what’s in the subject line when the message comes in.“D{MMsg}This message may contain the LoveLetter virus.” is the message that sendmail will give to the sender. You are free to be creative with this message and you could also create a universal error message for all of the mails with the subject line you want to block.

If you have a huge list of subject lines you want to block, you could do it this way:
LOCAL_RULESETS HSubject: $>Check_Subject
D{MPat2}Mother’s Day Order Confirmation
D{MPat3}Important ! Read carefully !!
D{MMsg}Your mail has been rejected because it may have a virus. SCheck_Subject
R${MPat} $*$#error $: 550 ${MMsg}
RRe: ${MPat} $*$#error $: 550 ${MMsg}
R${MPat2} $*$#error $: 550 ${MMsg}
RRe: ${MPat2} $*$#error $: 550 ${MMsg}
R${MPat3} $*$#error $: 550 ${MMsg}
RRe: ${MPat3} $*$#error $: 550 ${MMsg}


Hopefully, you get the idea here. After all this, you have to recompile the file and restart sendmail for this to take effect. To recompile the file:
1 – backup your original /etc/mail/
2 – in the /usr/lib/mail/cf directory, run:
/usr/ccs/bin/m4 ../m4/cf.m4 > /etc/mail/ To restart sendmail:
/etc/init.d/sendmail stop
/etc/init.d/sendmail start Have fun!]]>