{"id":172,"date":"2018-06-05T21:40:46","date_gmt":"2018-06-06T02:40:46","guid":{"rendered":"http:\/\/www.davidhedges.info\/?p=172"},"modified":"2018-06-05T21:40:46","modified_gmt":"2018-06-06T02:40:46","slug":"how-to-pull-ms-exchange-email-address-into-your-postfix-user-list","status":"publish","type":"post","link":"https:\/\/www.davidhedges.info\/index.php\/2018\/06\/05\/how-to-pull-ms-exchange-email-address-into-your-postfix-user-list\/","title":{"rendered":"How to pull MS Exchange email address into your postfix user-list"},"content":{"rendered":"<p>I&#8217;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.<\/p>\n<p>in \/etc\/postfix\/main.cf you will need to modify &#8220;smtpd_recipient_rectrictions&#8221; adding the following. I called my file user-list.<\/p>\n<ul>\n<li>&#8220;check_recipient_access hash:\/etc\/postfix\/user-list.db&#8221;<\/li>\n<\/ul>\n<p>Adding this will accept mail for email addresses that are listed in the file.<\/p>\n<p>On the Windows Exchange server, for this I&#8217;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.<\/p>\n<p>On the exchange server I use the following script:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">'==================================================================================================\r\n'\r\n' VBScript Source File \r\n'\r\n' NAME: LISTPROXYADDRESSES.VBS\r\n' VERSION: 0.9\r\n' AUTHOR: Bharat Suneja , Bharat Suneja\r\n' CREATE DATE  : 5\/06\/2004\r\n' LAST MODIFIED : 9\/23\/2005\r\n'==================================================================================================\r\n' COMMENT: \r\n'   \r\n'==================================================================================================\r\n\r\n'Set up constant for deleting values from multivalued attribute memberOf\r\n\r\nConst ADS_PROPERTY_NOT_FOUND  = &amp;h8000500D\r\nConst ADS_UF_ACCOUNTDISABLE = 2                       'For UserAccountControl\r\nConst strX400Search = \"X400\"\r\n'______________________________________________________\r\n\r\n'Set RootDSE\r\nSet objRootDSE = GetObject(\"LDAP:\/\/rootDSE\")\r\nstrDomain = objRootDSE.Get(\"defaultNamingContext\")\r\nstrADPath = \"LDAP:\/\/\" &amp; strDomain\r\n'wscript.Echo strADPath\r\nSet objDomain = GetObject(strADPath)\r\n'wscript.echo \"objDomain: \" &amp; objDomain.distinguishedName\r\n\r\n'Setup ADODB connection\r\nSet objConnection = CreateObject(\"ADODB.Connection\")\r\nobjConnection.Open \"Provider=ADsDSOObject;\"\r\nSet objCommand = CreateObject(\"ADODB.Command\")\r\nobjCommand.ActiveConnection = objConnection\r\n\r\n'Execute search command to look for Contacts &amp; Groups\r\n    objCommand.CommandText = _\r\n      \"&lt;\" &amp; strADPath &amp; \"&gt;\" &amp; \";(&amp;(|(objectClass=contact)(objectClass=group))(mail=*))\" &amp; \";distinguishedName,displayName,mail,proxyAddresses;subtree\"\r\n\r\n    'Execute search to get Recordset\r\n    Set objRecordSet = objCommand.Execute\r\n    \r\n        \r\n        'Start procedure\r\n        \r\n    strResult = strResult &amp; VbCrLf &amp; \"Domain: \" &amp; strDomain\r\n\r\n    strResult = strResult &amp; VbCrlf &amp;  \"#Total Records Found (other accounts): \" &amp; objRecordSet.RecordCount &amp; VbCrlf\r\n    AddressCount = 0\r\n\r\n       While Not objRecordSet.EOF 'Iterate through the search results\r\n \r\n            strUserDN = objRecordSet.Fields(\"distinguishedName\")     'Get User's distinguished name from Recordset into a string\r\n            set objUser= GetObject(\"LDAP:\/\/\"&amp; strUserDN &amp; \"\")         'Use string to bind to user object\r\n            \r\n\r\n\r\n                       strResult = strResult &amp; VbCrlf &amp;  \"cn: \" &amp; objUser.cn\r\n                       strResult = strResult &amp; VbCrlf &amp;  \"mail: \" &amp; objUser.mail\r\n                       arrProxyAddresses = objRecordSet.Fields(\"proxyAddresses\")\r\n                       If IsArray(objRecordSet.Fields(\"proxyAddresses\")) Then\r\n                       strResult = strResult &amp; VbCrLf &amp; \"Proxy Addresses\" \r\n               \r\n                          For Each ProxyAddress in arrProxyAddresses\r\n                          \r\n                            'Sub: Check X400 \r\n                             If InStr(ProxyAddress, strX400Search) &lt;&gt; 0 Then \r\n                        \t\t'Wscript.Echo \"#This was an x400\"\r\n                    \t\t Else\r\n                                     strResult = strResult &amp; VbCrlf &amp;  proxyAddress\r\n                              End If   'Ends loop for X400 address\r\n                Next\r\n\r\n            Else\r\n                strResult = strResult &amp; VbCrlf &amp;  \"#Object does not have proxy addresses\"\r\n            End If\r\n                strResult = strResult &amp;  VbCrLf\r\n\r\n     objRecordSet.MoveNext\r\nWend\r\n\r\n'*************************************\r\n'Begin second query for users\r\nvarDisabledCounter = 0                  \r\n\r\n'Execute search command to look for user\r\n    objCommand.CommandText = _\r\n      \"&lt;\" &amp; strADPath &amp; \"&gt;\" &amp; \";(&amp;(objectClass=user)(mail=*))\" &amp; \";distinguishedName,displayName,mail,proxyAddresses;subtree\"\r\n\r\n    'Execute search to get Recordset\r\n    Set objRecordSet = objCommand.Execute\r\n    \r\n    strResult = strResult &amp; vbCrlf &amp;  \"#Users\"\r\n    strResult = strResult &amp; VbCrlf &amp;  \"#Total Records Found (users): \" &amp; objRecordSet.RecordCount &amp; VbCrlf\r\n    \r\n\r\n\r\n       While Not objRecordSet.EOF 'Iterate through the search results\r\n            strUserDN = objRecordSet.Fields(\"distinguishedName\")     'Get User's distinguished name from Recordset into a string\r\n            set objUser= GetObject(\"LDAP:\/\/\"&amp; strUserDN &amp; \"\")         'Use string to bind to user object\r\n            \r\n            \r\n            If objUser.AccountDisabled = TRUE Then                    'If User account disabled, then skip proxy address enum\r\n               varDisabledCounter = varDisabledCounter + 1\r\n               strResult2 = strResult2 &amp; VbCrLf &amp; varDisabledCounter &amp; \" \" &amp; objUser.displayName &amp; VbCrLf\r\n               \r\n               strResult2 = strResult2 &amp; \"cn: \" &amp; objUser.cn\r\n                       strResult2 = strResult2 &amp; VbCrlf &amp;  \"mail: \" &amp; objUser.mail\r\n                       arrProxyAddresses = objRecordSet.Fields(\"proxyAddresses\")\r\n                       If IsArray(objRecordSet.Fields(\"proxyAddresses\")) Then\r\n                       strResult2 = strResult2 &amp; VbCrLf &amp; \"Proxy Addresses\" \r\n                       \r\n               \r\n                          For Each ProxyAddress in arrProxyAddresses\r\n                            'Sub: Check X400\r\n                             If InStr(ProxyAddress, strX400Search) &lt;&gt; 0 Then \r\n                        \t\t'Wscript.Echo \"#This was an x400\"\r\n                    \t\t Else\r\n                        \t\t strResult2 = strResult2 &amp; VbCrlf &amp;  proxyAddress\r\n                                 AddressCount = AddressCount + 1\r\n                              End If   'Ends loop for X400 address\r\n                          Next\r\n                              Else\r\n                                  strResult2 = strResult2 &amp; VbCrLf &amp;  \"#Object does not have proxy addresses\"\r\n                          End If\r\n                              strResult2 = strResult2 &amp;  VbCrLf\r\n               \r\n               \r\n               \r\n               \r\n               \r\n            Else\r\n            \r\n\r\n\r\n                       strResult = strResult &amp; VbCrlf &amp;  \"cn: \" &amp; objUser.cn\r\n                       strResult = strResult &amp; VbCrlf &amp;  \"mail: \" &amp; objUser.mail\r\n                       arrProxyAddresses = objRecordSet.Fields(\"proxyAddresses\")\r\n                       If IsArray(objRecordSet.Fields(\"proxyAddresses\")) Then\r\n                       strResult = strResult &amp; VbCrLf &amp; \"Proxy Addresses\" \r\n                          \r\n                          For Each ProxyAddress in arrProxyAddresses\r\n                            'Sub: Check X400\r\n                             If InStr(ProxyAddress, strX400Search) &lt;&gt; 0 Then \r\n                        \t\t'Wscript.Echo \"#This was an x400\"\r\n                    \t\t Else\r\n                        \t\t strResult = strResult &amp; VbCrlf &amp;  proxyAddress\r\n                                 AddressCount = AddressCount + 1\r\n                              End If   'Ends loop for X400 address\r\n                          Next\r\n                              Else\r\n                                  strResult = strResult &amp; VbCrLf &amp;  \"#Object does not have proxy addresses\"\r\n                          End If\r\n                              strResult = strResult &amp;  VbCrLf\r\n                \r\n          End If   'End check for disabled user \r\n            \r\n     objRecordSet.MoveNext \r\nWend  'End second query for users\r\n\r\n              \r\nstrResult = \"Users, Groups &amp; Contacts\" &amp; VbCrLf &amp; \"-------------------------\" &amp; VbCrLf &amp; strResult\r\nstrResult = strResult &amp; VbCrLf &amp; \"Disabled Users\" &amp; VbCrLf &amp; \"-------------------------\" &amp; VbCrLf &amp; strResult2\r\n'WScript.Echo strResult\r\n\r\n'Output to a text file\r\nSet objFileSystem = CreateObject(\"Scripting.FileSystemObject\")\r\nSet objOutputFile = objFileSystem.CreateTextFile(\"C:\\inetpub\\wwwroot\\postfix\\proxyaddresses.txt\")\r\nobjOutputFile.Write strResult\r\n\r\n\r\n     \r\n   \r\n\r\n\r\n            \r\n\r\n\r\n\r\n\r\n<\/pre>\n<p>You will want to modify the location that it places the file to the correct location for you &#8220;Set objOutputFile = objFileSystem.CreateTextFile(&#8220;C:\\inetpub\\wwwroot\\postfix\\proxyaddresses.txt&#8221;)&#8221;<\/p>\n<p>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.<\/p>\n<p>&nbsp;<\/p>\n<p>On the postfix server, I created the following script to pull the file from the exchange server and format it correctly for postfix:<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">#!\/bin\/bash\r\n#pull exhange user email \r\n#written by David Hedges \r\n\r\nmkdir \/tmp\/exch-users\r\ncd \/tmp\/exch-users\r\nwget http:\/\/&lt;YOUR SERVER IP or FQDN&gt;\/postfix\/proxyaddresses.txt\r\n\r\n#you may need to add sed statements for other domain extensions if you use one that is not listed\r\ngrep -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'  &gt;\/tmp\/exch-users\/user-list\r\n\r\n\r\n\/usr\/sbin\/postmap user-list\r\nmv .\/user-list.db \/etc\/postfix\/\r\nmv .\/user-list \/etc\/postfix\r\ncd \/tmp\r\nrm -R \/tmp\/exch-users\r\n<\/pre>\n<p>This will place both a plain text and a hash file in your \/etc\/postfix directory.<\/p>\n<p>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.<\/p>\n<p>Finally, you will need to restart your postfix instance for the change to read the user-list.db file to begin.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;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 &#8220;smtpd_recipient_rectrictions&#8221; adding the following. I called my file user-list. &#8220;check_recipient_access hash:\/etc\/postfix\/user-list.db&#8221; Adding this will accept mail for email addresses that are [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","footnotes":""},"categories":[3],"tags":[],"class_list":["post-172","post","type-post","status-publish","format-standard","category-it-blog","entry"],"_links":{"self":[{"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/posts\/172","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/comments?post=172"}],"version-history":[{"count":3,"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/posts\/172\/revisions"}],"predecessor-version":[{"id":175,"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/posts\/172\/revisions\/175"}],"wp:attachment":[{"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/media?parent=172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/categories?post=172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.davidhedges.info\/index.php\/wp-json\/wp\/v2\/tags?post=172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}