1
API - Obtain mailboxes Alias List for a Domain
Question asked by Rod Strumbel - 6/9/2022 at 11:32 AM
Answered
Hoping to find something in C# or VB.net code for this...

How can I obtain a full list of mailbox aliases associated with a domain ?

I use a system admin account for my automations, so I shouldn't have to do any sort of jumping thru hoops for impersonating any other accounts I wouldn't think.

I see a GetAlias (but that is not a LIST of aliases, it is a single alias return) and I see something for GetDomainAliases (but that returns aliases for the domain name itself).

This was simple in the old legacy API with a simple call in the svcAliasAdmin webservice to GetAliases passing in credentials and the domain name.  That operation does not appear to exist in the new API.


13 Replies

Reply to Thread
0
Zach Sylvester Replied
Employee Post
Hey Rod, 

Thanks for reaching out to the community.  To accomplish this you'd want to use the account list search. 

You'd have to use these two elements in your post request. 

Post request

https://mail.domain.com/api/v1/settings/domain/account-list-search

Json
{"skip":0,"take":"25","search":null,"sortField":"userName","sortDescending":false,"searchFlags":["aliases"]}
Please let me know if this helps. 

If you want an example I could make you an example in Python. 

Kind Regards, 
Zach Sylvester System/Network Administrator SmarterTools Inc. (877) 357-6278 www.smartertools.com
0
Rod Strumbel Replied
But... there is nothing in that to specify what domain you are searching... and I don't see anything in the return for that which shows which mailbox(es) the alias passed mail on to.  (other than if it is ALL mailboxes, I see a setting for that).

Am I misunderstanding ?
0
Zach Sylvester Replied
Employee Post
Hey Rod, 

Thanks for the follow-up. This is a domain admin call. So you need to either impersonate a domain admin via the API or use the domain admin credentials. Because it's a domain admin call specifying the domain is not required. 

Please let me know if this helps. 

Kind Regards, 
Zach Sylvester System/Network Administrator SmarterTools Inc. (877) 357-6278 www.smartertools.com
0
Rod Strumbel Replied
No... that's not gonna work for us as the domain admin name is inconsistent between domains.
And, I still don't see how pulling that information is going to tell me what mailbox(es) each alias points to.

This is for an evening process that pulls down the full list of domains.
For that list of domains it gathers the list of mailboxes.
For each mailbox it gets the current space in use, the list of forwards and the list of aliases that point at it, as well as the number of sent and received messages for the day.

That produced list then is trued up against our billing system to make sure all is accurate.

I have the process built using the legacy webservices, but was hoping to upgrade to using the newer API calls instead.   Guess that isn't happening as it sounds like the newer API is not capable of doing what I need (and have been doing for quite some time with the legacy services).
0
Zach Sylvester Replied
Employee Post
Hey Rod, 

I'm going to make you an example script. I will reply back shortly. 

Kind Regards, 
Zach Sylvester System/Network Administrator SmarterTools Inc. (877) 357-6278 www.smartertools.com
0
Zach Sylvester Replied
Employee Post
Hey Rod, 

Here's some example code. 
This code logs in to the system admin then it gets all the domains. After this, it gets all domain admins. 
After it does this it impersonates the domain admins and gets the aliases on the domain. Then returns it. 
Please note the domain must have included all domain users turned on for this to work. But you could edit the search flag more to find more alias without that needed. I hope this helps. 
import requests # imports the requests library
url = "http://domain.local"

def auth(username, password):
    global url 
    authurl = url + "/api/v1/auth/authenticate-user" 
    myobj = {'username': username, 'password':password} 
    data = requests.post(authurl, data = myobj) # this posts the username and password to the api
    #print(data.json())
    refreshToken = data.json()['refreshToken'] # this is the refresh token
    accessToken = data.json()['accessToken'] # this is the access token
    accessTokenExpiration = data.json()['accessTokenExpiration'] # this is the access token expiration date
    access_info = {'accessToken': accessToken, 'accessTokenExpiration': accessTokenExpiration, 'refreshToken': refreshToken} # this is the access token, refresh token and expiration info
    return access_info # returns the information



def impersonate_user(access_info, email):
    global url
    authurl = url + "/api/v1/settings/domain/impersonate-user/"+ email # this is the url of the impersonate user 
    data = requests.post(authurl, headers = {'Authorization': 'Bearer ' + access_info['accessToken']}) # this posts the user id to the api
    ImpersonatedUser_Token = data.json()['impersonateAccessToken'] # this is the impersonated user
    ImpersonatedUser_exp = data.json()['impersonateAccessTokenExpiration'] # this is the impersonated user
    data = {'impersonateAccessToken': ImpersonatedUser_Token, 'impersonateAccessTokenExpiration': ImpersonatedUser_exp} # this is the impersonated user token and expiration date
    return data # returns the impersonate access token



def get_domains(access_info):
    global url
    authurl = url + "/api/v1/settings/sysadmin/domain-list-search" # this is the url of the api
    body = {"sortField":"name","includeErrored":True}
    data = requests.post(authurl, headers = {'Authorization': 'Bearer ' + access_info['accessToken']}, json = body) # this posts the body to the api
    return data



def get_domainadmins(access_info):
    global url
    domainlist = get_domains(access_info)
    domainlist = domainlist.json()['results']
    #get domain admins
    admins = []
    for domain in domainlist:
        authurl = url + "/api/v1/settings/sysadmin/domain-admins/" + domain['name']
        data = requests.get(authurl, headers = {'Authorization': 'Bearer ' + access_info['accessToken']})
        data.json()
        admins = admins + data.json()['domainAdmins']
    return admins



def account_list_search(access_info):
    global url
    authurl = url + "/api/v1/settings/domain/account-list-search" # this is the url of the api
    body = {"skip":0,"take":"25","search":"null","sortField":"userName","sortDescending":False,"searchFlags":["aliases"]}
    data = requests.post(authurl, headers = {'Authorization': 'Bearer ' + access_info['impersonateAccessToken']}, json = body) # this posts the body to the api
    return data.json()





if __name__ == "__main__":
    admin = auth('admin', 'admin') #logs in as admin and gets the access token etc
    domainadmins = get_domainadmins(admin) # gets all the domain admins on the server
    domains = get_domains(admin) # gets all the domains on the server
    for domainadmins in domainadmins:
        user = impersonate_user(admin, domainadmins)
        results = (account_list_search(user))
        print(results)
               

Kind Regards, 
Zach Sylvester System/Network Administrator SmarterTools Inc. (877) 357-6278 www.smartertools.com
0
Rod Strumbel Replied
I translated the above to .Net HttpClient operations instead.
Doesn't matter what domain I access, the account-list-search comes up empty.

I'm no python expert, but can generally read it.
Changed the path in your script to our server and saved it as a .py file and ran it from the command line.

I get errors:  TypeError: string indices must be integers in get_domainadmins  domainlist = domainlist.json()['results'] (line 41) and then on line 66 as well with domainadmins = get_domainadmin(admin)

(was trying to run it to see if your scripts got different results than my .Net code does.)
0
Rod Strumbel Replied
Ok, I got the python script fixed, the script was fine, I had typo'd the password for the admin account.

Anyway... your script comes up with the same thing as my .Net code.   NO RESULTS.
There are definitely aliases out there but none are returned.
0
Zach Sylvester Replied
Employee Post
Hey Rod, 

Thanks for the follow-up. I took a look and changed the JSON payload. 
Please change the payload for the method to look like the following. 
def account_list_search(access_info):
    global url
    authurl = url + "/api/v1/settings/domain/account-list-search" # this is the url of the api
    body = {"searchFlags":["aliases"]}
    data = requests.post(authurl, headers = {'Authorization': 'Bearer ' + access_info['impersonateAccessToken']}, json = body) # this posts the body to the api
    return data.json()

That should work Please let me know if this helps. 

Kind Regards, 
Zach Sylvester System/Network Administrator SmarterTools Inc. (877) 357-6278 www.smartertools.com
0
Rod Strumbel Replied
Thanks Zach,

That returned results, but I am still not seeing how I can relate those results back to which mailboxes they act as aliases for:

An example return:

{'success': True, 'message': '', 'totalCount': 1, 'results': [{'userName': 'letters', 'displayName': None, 'status': 1, 'accountType': 4, 'authType': None, 'isEasEnabled': False, 'isMapiEwsEnabled': False, 'lastLoginTime': '0001-01-01T00:00:00', 'lastLoginProtocol': None, 'isWebmailEnabled': False, 'lastLogin': None, 'easLastLogin': None, 'mapiLastLogin': None, 'ewsLastLogin': None, 'isPopEnabled': False, 'popLastLogin': None, 'isImapEnabled': False, 'imapLastLogin': None, 'aliasTargetCount': 1, 'showInGAL': True, 'bytesUsedPercent': None, 'acceptedNewestPolicy': False, 'description': ''}]}

I know which domain I am in from the domain admin's email address, but the above is the alias:
'letters'
and should be for the mailbox
'editor@the_domain.com'

But that is not identified anywhere in the Json result that I see.

That relationship appears to be missing in the API reporting capability best I can tell.
0
Zach Sylvester Replied
Employee Post Marked As Answer
Hey Rod, 

I made another change and I also used another API call. To actually get the aliases subscribers you need to use the get-alias API call. This is also a domain admin call so we can do it while we get the aliases. 
Here is the updated code. 

Please let me know what you think. 

import requests # imports the requests library
url = "http://domain.local";

def auth(username, password):
    global url 
    authurl = url + "/api/v1/auth/authenticate-user" 
    myobj = {'username': username, 'password':password} 
    data = requests.post(authurl, data = myobj) # this posts the username and password to the api
    #print(data.json())
    refreshToken = data.json()['refreshToken'] # this is the refresh token
    accessToken = data.json()['accessToken'] # this is the access token
    accessTokenExpiration = data.json()['accessTokenExpiration'] # this is the access token expiration date
    access_info = {'accessToken': accessToken, 'accessTokenExpiration': accessTokenExpiration, 'refreshToken': refreshToken} # this is the access token, refresh token and expiration info
    return access_info # returns the information



def impersonate_user(access_info, email):
    global url
    authurl = url + "/api/v1/settings/domain/impersonate-user/"+ email # this is the url of the impersonate user 
    data = requests.post(authurl, headers = {'Authorization': 'Bearer ' + access_info['accessToken']}) # this posts the user id to the api
    ImpersonatedUser_Token = data.json()['impersonateAccessToken'] # this is the impersonated user
    ImpersonatedUser_exp = data.json()['impersonateAccessTokenExpiration'] # this is the impersonated user
    data = {'impersonateAccessToken': ImpersonatedUser_Token, 'impersonateAccessTokenExpiration': ImpersonatedUser_exp} # this is the impersonated user token and expiration date
    return data # returns the impersonate access token



def get_domains(access_info):
    global url
    authurl = url + "/api/v1/settings/sysadmin/domain-list-search" # this is the url of the api
    body = {"sortField":"name","includeErrored":True}
    data = requests.post(authurl, headers = {'Authorization': 'Bearer ' + access_info['accessToken']}, json = body) # this posts the body to the api
    return data



def get_domainadmins(access_info):
    global url
    domainlist = get_domains(access_info)
    domainlist = domainlist.json()['results']
    #get domain admins
    admins = []
    for domain in domainlist:
        authurl = url + "/api/v1/settings/sysadmin/domain-admins/" + domain['name']
        data = requests.get(authurl, headers = {'Authorization': 'Bearer ' + access_info['accessToken']})
        data.json()
        admins = admins + data.json()['domainAdmins']
    return admins



def account_list_search(access_info):
    global url
    authurl = url + "/api/v1/settings/domain/account-list-search" # this is the url of the api
    body = {"searchFlags":["aliases"]}
    data = requests.post(authurl, headers = {'Authorization': 'Bearer ' + access_info['impersonateAccessToken']}, json = body) # this posts the body to the api
    return data.json()


def get_alias_details(access_info, alias_name):
    global url
    authurl = url + "/api/v1/settings/domain/alias-get" # this is the url of the api
    body = {"name":alias_name}
    data = requests.post(authurl, headers = {'Authorization': 'Bearer ' + access_info['impersonateAccessToken']}, json = body) # this posts the body to the api
    return data.json()


if __name__ == "__main__":
    admin = auth('admin', 'admin') #logs in as admin and gets the access token etc
    domainadmins = get_domainadmins(admin) # gets all the domain admins on the server
    domains = get_domains(admin) # gets all the domains on the server
    for domainadmins in domainadmins:
        user = impersonate_user(admin, domainadmins)
        results = (account_list_search(user))
        print("-----------------------------------------------------")
        print("Domain Admin: " + domainadmins)
        print("-----------------------------------------------------")
        #print username
        for result in results['results']:
            
            c_username = result['userName']
            print(result['userName']) 
            c_alias_details = get_alias_details(user, c_username)
            c_alias_details = c_alias_details['alias']
            print(c_alias_details['aliasTargetList'])
        print("-----------------------------------------------------")
Zach Sylvester System/Network Administrator SmarterTools Inc. (877) 357-6278 www.smartertools.com
0
Rod Strumbel Replied
That works.  
I got it translated to .Net classes and such as well and functioning.
Kinda convoluted in how it must be done, but functional.

Thank  you. 


0
Zach Sylvester Replied
Employee Post
Hey Rod, 

Thanks for the follow-up. I'm happy that we got this figured out. Something to remember for the future is anything that can be done manually in the web interface can also be done at the API level. The reason for this is that the web interface actually uses the API. So if you're confused about something with the API you can often go to the same place in SmarterMail and click the button while the network monitor is up using inspect element and see what the web interface is doing to get the API function to work. 

I hope you have a great rest of your week. 

Kind Regards, 
Zach Sylvester System/Network Administrator SmarterTools Inc. (877) 357-6278 www.smartertools.com

Reply to Thread