Any decent MTA (mail server) should be able to route mail according to rules, instead of simply based on DNS. My experience is mostly with Exim, but Exim is not unique here.
Certainly with Exim it's almost trivial to write a Router which looks at the sender address to determine which host to send out by and put that before the normal dnslookup or smarthost Router. Add credentials adds a little complexity, but not much. The biggest question is really how do you want to store the data? LDAP? MySQL? CDB? Flat files? It all works. I don't use Exchange myself, but there are plenty of people using Exim in front of Exchange and relying on Exim's LDAP support to query AD for the data needed to not have to duplicate information.
For instance, as a non-trivial example implementing all your wishes, with some security on top, with a CDB file mapping customer domains to key="value" data for the domain, you might have:
key: example.com
value: server="smtp.example.com" user="fred" pass="s3kr3t" submission=t
and then:
# after "begin routers" and before the normal remote mail sending Router:
via_customer_server:
driver = manualroute
senders = *@cdb;/etc/mail/customers.cdb
transport = customer_server_t
address_data = ${lookup{$sender_address_domain}cdb{/etc/mail/customers.cdb}}
route_data = ${extract{server}{${lookup{$sender_address_domain}cdb{/etc/mail/customers.cdb}}}
# after "begin transports"
customer_service_t:
driver = smtp
hosts_require_auth = ${extract{user}{$address_data}{*}{}}
port = ${extract{submission}{$address_data}{587}{25}}
# these next two will mandate TLS if tls is present, and turn on cert verification
hosts_require_tls = ${extract{tls}{$address_data}{*}{}}
tls_verify_certificates = ${extract{tls}{$address_data}{/etc/ssl/certs}{}}
# after "begin authenticators"
auth_plain:
driver = plaintext
public_name = PLAIN
client_condition = ${if def:tls_cipher}
client_send = ^${extract{user}{$address_data}}^${extract{pass}{$address_data}}
As a couple of notes: address_data on the Router preserved the lookup results for easy access later, route_data did the same lookup, but in practice that will be use the cached results of the address_data, and this is a rather complete, albeit untested, example.
You can do other stuff instead of cdb, I just chose that at random. In particular, LDAP searches for multiple attributes will return data in the right format for the ${extract...} expansion operator to work with, so this should be good if you want to put the data into AD.