0

My client has got many sub-offices, and one head office. The headoffice has a domain name: business.com

All users in the many sub-offices need to have a headoffice email address: [email protected] Anyone not in the head office will need the email forwarded to an external email address. All users in the head office will have their email delivered to Microsoft Exchange. Users are listed in Active Directory under two different OU's: HeadOffice or SubOffice.

Is this something able to be configured? I've done some googling, but I can't find any examples or businesses set up this way.

Edit: Postfix will accept all email, will need to determine to forward the email to an external account or alternatively have it delivered to MS Exchange.

I've done some reading about MS Exchange and that you can 'mail-enable' contacts for forwarding - but I don't know if each AD account requires an Exchange CAL?

The end goal is to forward email to external accounts to sub offices or accept email for head office.

Maybe I don't need to worry about Postfix to perform this task.....

http://www.windowsitpro.com/article/exchange-server-2010/exchange-server-licensing-some-of-your-questions-answered

"What about client access licenses (CALs)? You need one CAL per user who will connect to Exchange. Although it might not be 100 percent precise, I prefer to think of it as one CAL per mailbox; there are exceptions for users outside your organization, automated tools that use mailboxes, and so on. Exchange doesn't enforce this limit, so it's on you to ensure that you have the correct number of CALs for the set of clients you support."

2
  • It would be helpful to know more about your topology. Where does postfix fit in to the flow of email? Where is Exchange exactly. Is it postfix on Windows or *nix? Does postfix's server communicate with Active Directory? A lot is unclear.
    – Wesley
    Jul 2, 2012 at 5:26
  • Postfix would accept all email for delivery, check whether it needs to forward to an internal exchange server, or forward out to an external email account.
    – itwb
    Jul 2, 2012 at 6:09

1 Answer 1

2

Whilst not strictly speaking answering your question, what you are trying to achieve should be fairly easy with a few modifications to the perl script below.

The perl script queries active directory and returns a list of email addresses within the specified OU matching the patterns in the script, and then regenerates the configuration file that postfix uses to determine valid email addresses that it needs to accept email for.

The perl script is called by a bash script, which is initiated via cron.

With some work, it should be fairly easy to tweak the scripts to allow you to do what you need.

Note that you will need to create a user in AD with the details specified in the perl script, and that user account requires read access to the relevant objects in your AD.

$hqbase determines the container that will be searched for email addresses.

Create the following bash script, which is initiated via cron:

#!/bin/bash
# Get the email addresses from AD, if it fails exit the script
/root/getadsmtp.pl || exit
# Now convert the list into a file that postfix can understand
/usr/sbin/postmap /etc/postfix/exchange_recipients

The following is the file getadsmtp.pl, which is called from the above shell script. You will need to modify this to get the results you are looking for.

use Net::LDAP;
use Net::LDAP::Control::Paged;
use Net::LDAP::Constant ( "LDAP_CONTROL_PAGED" );

$VALID = "/etc/postfix/exchange_recipients";

$dc1="dc1.example.local";
$dc2="dc2.example.local";

$hqbase="ou=foo,dc=example,dc=com";

$user="cn=postfix_xfer,ou=Services,ou=users,ou=foo,dc=example,dc=com";
$passwd="passwordgoeshere";

$noldapserver=0;
$ldap = Net::LDAP->new($dc1) or
   $noldapserver=1;
if ($noldapserver == 1)  {
   $ldap = Net::LDAP->new($dc2) or
      die "Error connecting to specified domain controllers $@ \n";
}

$mesg = $ldap->bind ( dn => $user,
                     password =>$passwd);
if ( $mesg->code()) {
    die ("error:", $mesg->code(),"\n","error name: ",$mesg->error_name(),
        "\n", "error text: ",$mesg->error_text(),"\n");
}

$page = Net::LDAP::Control::Paged->new( size => 990 );

@args = ( base     => $hqbase,
         filter => "(& (mailnickname=*) (| (&(objectCategory=person)
                    (objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))
                    (&(objectCategory=person)(objectClass=user)(|(homeMDB=*)
                    (msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=contact))
                    (objectCategory=group)(objectCategory=publicFolder)(objectClass=msExchDynamicDistributionList) ))",
          control  => [ $page ],
          attrs  => "proxyAddresses",
);

my $cookie;
while(1) {
  # Perform search
  my $mesg = $ldap->search( @args );

  foreach my $entry ( $mesg->entries ) {
    my $name = $entry->get_value( "cn" );
    # LDAP Attributes are multi-valued, so we have to print each one.
    foreach my $mail ( $entry->get_value( "proxyAddresses" ) ) {
     # Test if the Line starts with one of the following lines:
     # proxyAddresses: [smtp|SMTP]:
     # and also discard this starting string, so that $mail is only the
     # address without any other characters...
     if ( ( $mail =~ s/^(smtp|SMTP)://gs ) &&
          ( ( $mail =~ m/example.co.uk/ ) ||
            ( $mail =~ m/example.com/ ) ||
            ( $mail =~ m/example.org/ ) ||
            ( $mail =~ m/example.net/ ) ) ) {
       push(@valid, $mail." OK\n");
     }
    }
  }

  # Only continue on LDAP_SUCCESS
  $mesg->code and last;

  # Get cookie from paged control
  my($resp)  = $mesg->control( LDAP_CONTROL_PAGED ) or last;

  $cookie    = $resp->cookie or last;

  # Set cookie in paged control
  $page->cookie($cookie);
}

if ($cookie) {
  # We had an abnormal exit, so let the server know we do not want any more
  $page->cookie($cookie);
  $page->size(0);
  $ldap->search( @args );
  # Also would be a good idea to die unhappily and inform OP at this point
     die("LDAP query unsuccessful");
}
open VALID, ">$VALID" or die "CANNOT OPEN $VALID $!";
print VALID @valid;

close VALID;

Hopefully this will be of some help to you.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .