### router/900_exim4-config_local_user ################################# # These routers deal with mail meant for virtual_domains and real_domains. # The targets for addresses in these domains and hosts are taken from # the LDAP server. # # The first two routers check the LDAP directory to find an object to # which the mail should be delivered. The first one works on # virtual_domains, and finds an object based on the mail or # alternateMailAddress attributes. For example, info@stdin.nl might be # resolved by that one. The second one works on real_domains and finds an # object based its uid (i.e., username). For example, # matthijs@login.drsnuggles.stderr.nl might be resolved by the second # router. # # The next set of routers works when a person is retrieved. They handle # forwarding the mail to another mail server when the mailHost attribute # is set but it is not us, forwarding the email to any # mailForwardingAddresses in the object or delivering the mail locally # when the mailHost is set. Note that both either or both of the last # two routers can apply. If none of these three apply, routing continues # to the last set. Local delivery works by redirecting to username@localhost # and redirecting to the local_delivery router. This allows for a number of # different routers (put after the local_delivery router) to handle the # local_delivery. This is also the only way to get to any routers after the # ones in this file! # # The last two routers work when a group is retrieved. They handle # forwarding the mail to any members, both rfc822members (ie, addresses) # and uniqueMembers (ie, other LDAP objects). # # Note that this distinction between persons and groups is not made by # looking at the object classes, but at the attributes. Any object that # has a mailHost and/or mailForwardingAddresses is treated as a person, # meaning that only these two attributes are processed. Any object that # has neither of these attributes is assumed to be a group and has its # rfc822members and uniqueMembers processed. Any object that has none of # these properties, will cause a delivery failure. # # Note also that only the first two routers have the domains # precondition set, to differentiate between virtual_domains and # real_domains. Assuming that the routers in this file will only be called for # virtual_domains and real_domains, exactly one of these two routers will be # called. If the lookup fails, the more option ensures that the rest of the # routers are not called. # # The routers in this file assume that the url to LDAP server is defined # as LDAPSERVER and the base dn is defined as LDAPBASE. No assumptions # are made about the structure of the LDAP directory, so any object that # has the mail or mailForwardingAddress attributes is considered a # valid target for email, anywhere in the directory. These routers do # assume that a single email address is listed only once. If not, mails # to the address will be deferred. LDAPURL=LDAPSERVER/LDAPBASE # This router looks up an object in the ldap directory using its mail and # alternateMailAddress attributes, for any domains in virtual_domains. # This handles email addresses in "virtual" domains, since the object # found does not need to actually have a username (it can even be a # group). ADDR=${quote_ldap:${local_part}@${domain}} ldap_lookup_virtual: debug_print = "R: ldap_lookup_virtual for $local_part@$domain: Finding person or group with (alternate) email address $local_part@$domain" driver = redirect domains = +virtual_domains address_data = ${lookup ldap {LDAPURL?uid,mailHost,mailForwardingAddress,rfc822member,uniqueMember?sub?(|(mail=ADDR)(mailAlternateAddress=ADDR))}{$value}fail} # Noop, this router just needs to pass its preconditions, evaluate # address_data and then pass control to ldap_person_other_mailhost below data = ${local_part}@${domain} redirect_router=ldap_person_other_mailhost # If no objects are found and the address_data expansion is forced to fail, # stop processing. Note that this setting does not apply when the domains # precondition fails. more = false cannot_route_message = "Unknown address" # This router looks up an object in the ldap directory using its uid # (username) attribute, for any hosts in real_domains. This handles email # addresses of actual users in this domain, i.e., objects that have uid # property. LOCALPART=${quote_ldap:${local_part}} ldap_lookup_real: debug_print = "R: ldap_lookup_real for $local_part@$domain: Finding user with uid $local_part" driver = redirect domains = +real_domains address_data = ${lookup ldap {LDAPURL?uid,mailHost,mailForwardingAddress?sub?(uid=LOCALPART)}{$value}fail} # Noop, this router just needs to pass its preconditions, evaluate # address_data and then pass control to ldap_person_other_mailhost below data = ${local_part}@${domain} redirect_router=ldap_person_other_mailhost # If no objects are found and the address_data expansion is forced to fail, # stop processing. Note that this setting does not apply when the domains # precondition fails. more = false cannot_route_message = "Unknown user" # If the person has a mailhost configured, and it's not us, forward to # that mailhost. If this router accepts, no others will be tried. This # means we're also not processing any mailForwardingAddresses, assuming # that the host forwarded to will do this. # # This entry is mostly future-compatible, since at the time of writing # there are no other mailservers using the same LDAP directory. But it # looks cool! ldap_person_other_mailhost: debug_print = "R: ldap_person_other_mailhost for $local_part@$domain: Forwarding to a mailHost if it is not us" driver = manualroute condition = ${if and { \ # If mailhost is not empty {!eqi{${extract{mailHost}{$address_data}}}{}} \ # And mailhost is not this host {!eqi{${extract{mailHost}{$address_data}}}{$primary_hostname}} \ }} # Then, forward to the other mailHost route_data = ${extract{mailHost}{$address_data}} transport = remote_smtp # Forward the mail to any mailForwardingAddresses configured DELIVER_HERE=${if eqi{${extract{mailHost}{$address_data}}}{$primary_hostname}{true}{false}} ldap_person_forward: debug_print = "R: ldap_person_forward for $local_part@$domain: Forwarding to any mailForwardingAddresses" driver = redirect data = ${extract{mailForwardingAddress}{$address_data}} # Pass the message to the ldap_person_local router as well, so we can support both # local delivery and forwarding. However, only set unseen to yes if we know # the ldap_person_local will accept it. Just putting unseen = yes here doesn't # work because if there is no local delivery, an error message is generated # even when the email was forwarded succesfully. unseen = DELIVER_HERE # Deliver the mail locally if the mailHost points to us. ldap_person_local: debug_print = "R: ldap_person_local for $local_part@$domain: Doing local delivery if the mailHost is us" driver = redirect # Lookup if there is a user that has the target email address in either his # mail attribute, or one of his mailAlternateAddresses and also has his # mailstore on this host as its mailhost. condition = DELIVER_HERE # Forward the email to username@localhost. There is a separate set of routers # that explicitly handles the localhost "domain", and has support for things # like .forward files, procmail, etc. data = ${extract{uid}{$address_data}}@localhost redirect_router = local_delivery # If any of the two above routers accepted the message, processing will # stop here! # Forward the mail to any full members (uniqueMember) configured ldap_group_member: debug_print = "R: ldap_group_member for $local_part@$domain: Forwarding to any uniqueMembers" driver = redirect # Lookup the mail address (if any) of each member. This gracefully ignores # any members without an email address. data = ${map \ # Since multipe attributes are separated by ", ", we replace ", " by "\n" # and use that as a list separator (fortunately it's not just ",", as the # documentation suggests, since then we would have had one big dn...) {<\n ${sg \ {${extract{uniqueMember}{$address_data}}} \ {, } \ {\n} \ }} \ {${lookup ldap {LDAPSERVER/$item?mail?base?}}} \ } # Pass the message to the ldap_group_address router as well, so we can support both # addresses (rfc822member) and dns (uniqueMember) in a group. # However, only set unseen to yes if we know the ldap_group_address will # accept it. Just putting unseen = yes here doesn't work because if there is # no local delivery, an error message is generated even when the email was # already forwarded succesfully. unseen = ${if !eqi{${extract{rfc822member}{$address_data}}}{}{true}{false}} # Forward the mail to any mail-only members (rfc822member) configured ldap_group_address: debug_print = "R: ldap_group_address for $local_part@$domain: Forwarding to any rfc822members" driver = redirect data = ${extract{rfc822member}{$address_data}} cannot_route_message = "Recipient is not set up for mail reception" # If this router did not match, stop processing. more = false # vim: set sts=2 expandtab sw=2 ai: