I’ve used this in the past to limit the amount of SPAM by only allowing relay back to my exchange server of email addresses that are valid.
in /etc/postfix/main.cf you will need to modify “smtpd_recipient_rectrictions” adding the following. I called my file user-list.
- “check_recipient_access hash:/etc/postfix/user-list.db”
Adding this will accept mail for email addresses that are listed in the file.
On the Windows Exchange server, for this I’ll assume we are using OWA and we can drop the list of addresses within the inetpub directory, allowing us to pick it up using wget.
On the exchange server I use the following script:
'==================================================================================================
'
' VBScript Source File
'
' NAME: LISTPROXYADDRESSES.VBS
' VERSION: 0.9
' AUTHOR: Bharat Suneja , Bharat Suneja
' CREATE DATE : 5/06/2004
' LAST MODIFIED : 9/23/2005
'==================================================================================================
' COMMENT:
'
'==================================================================================================
'Set up constant for deleting values from multivalued attribute memberOf
Const ADS_PROPERTY_NOT_FOUND = &h8000500D
Const ADS_UF_ACCOUNTDISABLE = 2 'For UserAccountControl
Const strX400Search = "X400"
'______________________________________________________
'Set RootDSE
Set objRootDSE = GetObject("LDAP://rootDSE")
strDomain = objRootDSE.Get("defaultNamingContext")
strADPath = "LDAP://" & strDomain
'wscript.Echo strADPath
Set objDomain = GetObject(strADPath)
'wscript.echo "objDomain: " & objDomain.distinguishedName
'Setup ADODB connection
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection
'Execute search command to look for Contacts & Groups
objCommand.CommandText = _
"<" & strADPath & ">" & ";(&(|(objectClass=contact)(objectClass=group))(mail=*))" & ";distinguishedName,displayName,mail,proxyAddresses;subtree"
'Execute search to get Recordset
Set objRecordSet = objCommand.Execute
'Start procedure
strResult = strResult & VbCrLf & "Domain: " & strDomain
strResult = strResult & VbCrlf & "#Total Records Found (other accounts): " & objRecordSet.RecordCount & VbCrlf
AddressCount = 0
While Not objRecordSet.EOF 'Iterate through the search results
strUserDN = objRecordSet.Fields("distinguishedName") 'Get User's distinguished name from Recordset into a string
set objUser= GetObject("LDAP://"& strUserDN & "") 'Use string to bind to user object
strResult = strResult & VbCrlf & "cn: " & objUser.cn
strResult = strResult & VbCrlf & "mail: " & objUser.mail
arrProxyAddresses = objRecordSet.Fields("proxyAddresses")
If IsArray(objRecordSet.Fields("proxyAddresses")) Then
strResult = strResult & VbCrLf & "Proxy Addresses"
For Each ProxyAddress in arrProxyAddresses
'Sub: Check X400
If InStr(ProxyAddress, strX400Search) <> 0 Then
'Wscript.Echo "#This was an x400"
Else
strResult = strResult & VbCrlf & proxyAddress
End If 'Ends loop for X400 address
Next
Else
strResult = strResult & VbCrlf & "#Object does not have proxy addresses"
End If
strResult = strResult & VbCrLf
objRecordSet.MoveNext
Wend
'*************************************
'Begin second query for users
varDisabledCounter = 0
'Execute search command to look for user
objCommand.CommandText = _
"<" & strADPath & ">" & ";(&(objectClass=user)(mail=*))" & ";distinguishedName,displayName,mail,proxyAddresses;subtree"
'Execute search to get Recordset
Set objRecordSet = objCommand.Execute
strResult = strResult & vbCrlf & "#Users"
strResult = strResult & VbCrlf & "#Total Records Found (users): " & objRecordSet.RecordCount & VbCrlf
While Not objRecordSet.EOF 'Iterate through the search results
strUserDN = objRecordSet.Fields("distinguishedName") 'Get User's distinguished name from Recordset into a string
set objUser= GetObject("LDAP://"& strUserDN & "") 'Use string to bind to user object
If objUser.AccountDisabled = TRUE Then 'If User account disabled, then skip proxy address enum
varDisabledCounter = varDisabledCounter + 1
strResult2 = strResult2 & VbCrLf & varDisabledCounter & " " & objUser.displayName & VbCrLf
strResult2 = strResult2 & "cn: " & objUser.cn
strResult2 = strResult2 & VbCrlf & "mail: " & objUser.mail
arrProxyAddresses = objRecordSet.Fields("proxyAddresses")
If IsArray(objRecordSet.Fields("proxyAddresses")) Then
strResult2 = strResult2 & VbCrLf & "Proxy Addresses"
For Each ProxyAddress in arrProxyAddresses
'Sub: Check X400
If InStr(ProxyAddress, strX400Search) <> 0 Then
'Wscript.Echo "#This was an x400"
Else
strResult2 = strResult2 & VbCrlf & proxyAddress
AddressCount = AddressCount + 1
End If 'Ends loop for X400 address
Next
Else
strResult2 = strResult2 & VbCrLf & "#Object does not have proxy addresses"
End If
strResult2 = strResult2 & VbCrLf
Else
strResult = strResult & VbCrlf & "cn: " & objUser.cn
strResult = strResult & VbCrlf & "mail: " & objUser.mail
arrProxyAddresses = objRecordSet.Fields("proxyAddresses")
If IsArray(objRecordSet.Fields("proxyAddresses")) Then
strResult = strResult & VbCrLf & "Proxy Addresses"
For Each ProxyAddress in arrProxyAddresses
'Sub: Check X400
If InStr(ProxyAddress, strX400Search) <> 0 Then
'Wscript.Echo "#This was an x400"
Else
strResult = strResult & VbCrlf & proxyAddress
AddressCount = AddressCount + 1
End If 'Ends loop for X400 address
Next
Else
strResult = strResult & VbCrLf & "#Object does not have proxy addresses"
End If
strResult = strResult & VbCrLf
End If 'End check for disabled user
objRecordSet.MoveNext
Wend 'End second query for users
strResult = "Users, Groups & Contacts" & VbCrLf & "-------------------------" & VbCrLf & strResult
strResult = strResult & VbCrLf & "Disabled Users" & VbCrLf & "-------------------------" & VbCrLf & strResult2
'WScript.Echo strResult
'Output to a text file
Set objFileSystem = CreateObject("Scripting.FileSystemObject")
Set objOutputFile = objFileSystem.CreateTextFile("C:\inetpub\wwwroot\postfix\proxyaddresses.txt")
objOutputFile.Write strResult
You will want to modify the location that it places the file to the correct location for you “Set objOutputFile = objFileSystem.CreateTextFile(“C:\inetpub\wwwroot\postfix\proxyaddresses.txt”)”
After testing this I also created a scheduled task on the exchange server to run this every 15 min. This way when users are added or new email addresses are created they will automatically be placed in a location where they can be picked up by our postfix server.
On the postfix server, I created the following script to pull the file from the exchange server and format it correctly for postfix:
#!/bin/bash #pull exhange user email #written by David Hedges mkdir /tmp/exch-users cd /tmp/exch-users wget http://<YOUR SERVER IP or FQDN>/postfix/proxyaddresses.txt #you may need to add sed statements for other domain extensions if you use one that is not listed grep -i smtp proxyaddresses.txt |grep -v ADdomain.local |sed 's/smtp://g' |sed 's/SMTP://g'|sed 's/\.com/\.com\tOK/g' |sed 's/\.COM/\.COM\tOK/g' |sed 's/\.net/\.net\tOK/g' |sed 's/\.NET/\.NET\tOK/g' |sed 's/\.tv/\.tv\tOK/g' |sed 's/\.TV/\.TV\tOK/g' |sed 's/\.org/\.org\tOK/g' |sed 's/\.ORG/\.ORG\tOK/g' |sed 's/\.info/\.info\tOK/g' |sed 's/\.INFO/\.INFO\tOK/g' | sed 's/\.us/\.us\tOK/g' | sed 's/\.US/\.US\tOK/g' >/tmp/exch-users/user-list /usr/sbin/postmap user-list mv ./user-list.db /etc/postfix/ mv ./user-list /etc/postfix cd /tmp rm -R /tmp/exch-users
This will place both a plain text and a hash file in your /etc/postfix directory.
For this I also created a cron job to run it every 5 min. That way it will pick up the changes as the exchange host publishes them.
Finally, you will need to restart your postfix instance for the change to read the user-list.db file to begin.
Leave a Reply