Python API Wrapper Tutorial
This document introduces the Python API library which allows you to administer your MailStore Service Provider Edition via Python.
Installation
The API library is tested against Python 3.2 to Python 3.4. It is compatible with the 32bit and the 64bit versions of Python.
You can get your Python binary from the Python download page or you can install it using the package manager of you distribution.
Additionally you need the MailStore API library which has to be installed in your Python's site-packages mailstore directory. The location of the site-packages directory can be found with the following command
python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"
Log in
The library can be imported with
import mailstore
You are able to instantiate the class directly
speClient = mailstore.spe.Client(username="admin", password="admin", host="127.0.0.1", port=8470)
or by using the with statement (context manager)
with mailstore.spe.Client(password="S3cR3t!", host="spe.domain.eu") as speClient:
do_something()
Default values can be omitted.
The available log in arguments and default values are
username = "admin"
password = "admin"
host = "127.0.0.1"
port = 8470
autoHandleToken = True
waitTime = 2000
logLevel = 2
fileLogLevel = 0
When autoHandleToken is enabled, you do not have to care about long running processes, you just have to wait for the result. When this value is set to False, then the status token is returned and you have to handle the token manually. More about this later.
The waitTime value specifies the value that is passed to the get-status call. When you call a long running method like VerifyStore, this is the maximum amount of milliseconds you have to wait for a status update.
logLevel and fileLogLevel have to be in the range 0 to 4. The loglevels are defined as following
0 : "NONE" 1 : "ERROR" 2 : "WARNING" 3 : "INFO" 4 : "DEBUG"
Log entries will be printed to stdout. The logfile will be created in the user's %temp% directory and starts with the prefix MailStorePyLib. logLevel and fileLogLevel do not have to match.
Log out
When you prefer the first log in method, you have to log out afterwards manually. When using the context manager method, the log out is done automatically when exiting the with block. The logoutHandler will close open log files, if necessary.
speClient.logoutHandler()
Simple calls
Simple calls will return immediately
print(speClient.GetEnvironmentInfo())
{'antiXsrfToken': 'dUubPmGWEANyDxGbBvejCu6qSRUlkQYSiunQCGFkbWlu', 'logOutput': None, 'statusText': None, 'error': None, 'percentProgress': None, 'token': None, 'result': {'userName': 'admin', 'copyright': 'Copyright (c) 2005-2013 MailStore Software GmbH', 'systemProperties': {'totalPhysicalMemory': 2146947072, 'processors': ['Intel(R) Core(TM) i5-2400 CPU @ 3.10GHz'], 'operatingSystem': 'Microsoft Windows Server 2012 Standard'}, 'serverName': 'win2012spe', 'version': '8.5.0.9288', 'licenseeName': 'MailStore Software GmbH', 'licenseeID': 1}, 'statusVersion': 2, 'statusCode': 'succeeded'}
When the statusCode is succeeded the information is stored in the result field. When the process has ended with another status, like failed or cancelled the diagnosis information is stored in the error field.
When there are no HTTP errors, the returned value is always a python dictionary.
Simple examples
To get all user's detailed information you could
with mailstore.spe.Client():
instance = "test01"
for user in speClient.GetUsers(instance)["result"]:
print(speClient.GetUserInfo(instance, user["userName"])["result"])
A list with all assigned email address can be retrieved with
with mailstore.spe.Client() as client:
instID = "test01"
emailaddresses = list()
for user in client.GetUsers(instID)["result"]:
info = client.GetUserInfo(instID, user["userName"])["result"]
emailaddresses += info['emailAddresses']
print(emailaddresses)
Long running calls
Long running calls like VerifyStore are running asynchronous on the instance. When autoHandleToken is set to True (default), the library polls the status in the background automatically and will return the final result when the process has ended. Set autoHandleToken to False to get the token. In this case you have to handle the token by yourself. There are helper methods available.
with mailstore.spe.Client(autoHandleToken=False) as client:
instID = "test01"
storeID = 1
print(client.VerifyStore(instID, storeID))
{'antiXsrfToken': '6h8HV67XSak+jpQ/e6X1ehLOrt9cPUGicfHQCGFkbWlu', 'logOutput': None, 'statusText': None, 'error': None, 'percentProgress': None, 'token': 'sa6431dcd1b3e48c4719cfe8a75612b88a', 'result': None, 'statusVersion': 0, 'statusCode': 'running'}
You are able to update the status manually by passing the token to the GetStatus method. The call has finished, when the statusCode has changed from running to something else.
with mailstore.spe.Client(autoHandleToken=False) as client:
instID = "test01"
storeID = 1
token = client.VerifyStore(instID, storeID))
time.sleep(5)
print(client.GetStatus(token))
{'antiXsrfToken': '+MKktayBhloqEsqk3xNTssdwTHRxL5+UaPTQCGFkbWlu', 'logOutput': ' 100 messages verified...\r\n 200 messages verified...\r\n 300 messages verified...\r\n 400 messages verified...\r\n 500 messages verified...\r\n 600 messages verified...\r\n 700 messages verified...\r\n', 'statusText': None, 'error': None, 'percentProgress': 17, 'token': 'sa92c717e75db26fa57fc09c5e95f7096d', 'result': None, 'statusVersion': 29, 'statusCode': 'running'}
One could pass the token to the HandleToken method, then the behavior is exactly the same, as when you would have set autoHandleToken=True.
with mailstore.spe.Client(autoHandleToken=False) as client:
instID = "test01"
storeID = 38
token = client.VerifyStore(instID, storeID)
print(client.HandleToken(token))
{'antiXsrfToken': 'KIMJdCpjcuD8O5+xPislG8OysJ0fPgXQcvHQCGFkbWlu', 'logOutput': 'Verifying file group #38...\r\nCreating a list of messages to be verified...\r\n389 messages are about to be verified.\r\nVerifying...\r\n 100 messages verified...\r\n 200 messages verified...\r\n 300 messages verified...\r\n 389 messages verified...\r\nFinished. No errors have been found.\r\n', 'statusText': None, 'error': None, 'percentProgress': 100, 'token': 'sa8e56590b28b3c57f076168d5913840df', 'result': None, 'statusVersion': 147, 'statusCode': 'succeeded'}
Alternatively one could pass the token to the HandleTokenIter method, then every status update is yielded.
with mailstore.spe.Client(autoHandleToken=False) as client:
instID = "test01"
storeID = 38
for status in client.HandleTokenIter(client.VerifyStore(instID, storeID)):
print(status)
{'antiXsrfToken': 'DEF2dWnoNl7hkgsHqApPZmpsUqEgpih6c/HQCGFkbWlu', 'logOutput': 'Verifying file group #38...\r\nCreating a list of messages to be verified...\r\n389 messages are about to be verified.\r\nVerifying...\r\n', 'statusText': None, 'error': None, 'percentProgress': 0, 'token': 'safd22a51408925dd787ef43a5adc3772c', 'result': None, 'statusVersion': 5, 'statusCode': 'running'}
{'antiXsrfToken': 'a3NMb7VdnLaTOOnfyJnZWEutbmlzPXd6c/HQCGFkbWlu', 'logOutput': None, 'statusText': None, 'error': None, 'percentProgress': 1, 'token': None, 'result': None, 'statusVersion': 6, 'statusCode': 'running'}
{'antiXsrfToken': 'mi8qpqTdw6hoH+/+o6h65Rx0jiuPR4p6c/HQCGFkbWlu', 'logOutput': ' 100 messages verified...\r\n', 'statusText': None, 'error': None, 'percentProgress': 1, 'token': None, 'result': None, 'statusVersion': 7, 'statusCode': 'running'}
[...]
You are able to set the token handling behavior globally and locally. When you instantiate the client with autoHandleToken=True you still are able to call every long running method with autoHandleToken=False and vice versa. Methods that do not return a token, do not accecpt the autoHandleToken parameter.
with mailstore.spe.Client(autoHandleToken=True) as client:
instID = "test01"
client.MaintainFileSystemDatabases(instID, autoHandleToken=False)
Cancelling long running calls
If you want to cancel a long running call, you have to pass the token of that call to the CancelAsync method
import time
with mailstore.spe.Client(autoHandleToken=False) as client:
instID = "test01"
storeID = 38
token = client.VerifyStore(instID, storeID)
time.sleep(2)
print(client.CancelAsync(token))
time.sleep(2)
print(client.GetStatus(token))
{'antiXsrfToken': 'DUs5EO8ZZ9A8S6lUB/uYwIsAFwTufVpCd/HQCGFkbWlu', 'logOutput': None, 'statusText': None, 'error': None, 'percentProgress': None, 'token': None, 'result': None, 'statusVersion': None, 'statusCode': None}
{'antiXsrfToken': 'fYO6hoP7eKr1X1SDj++6hhwI9pTwD45Dd/HQCGFkbWlu', 'logOutput': 'Verifying file group #38...\r\nCreating a list of messages to be verified...\r\n3893 messages are about to be verified.\r\nVerifying...\r\n 100 messages verified...\r\n 200 messages verified...\r\n 300 messages verified...\r\n', 'statusText': None, 'error': None, 'percentProgress': 7, 'token': None, 'result': None, 'statusVersion': 17, 'statusCode': 'cancelled'}
Pretty Printing the output
There is a helper function that formats the returned values in more readable manner.
mailstore.pprint(client.GetUserInfo("test01","admin"))
antiXsrfToken lVKkLrjBXeg7KcjdZ/n6050bpfdAILI9F/3QCGFkbWlu
result
userName admin
privileges
admin
authentication integrated
fullName admin
statusVersion 2
statusCode succeeded
The CallMethod method
The signature of the CallMethod method is
CallMethod(self, methodname, arguments = {}, autoHandleToken = None)
This is the most low-level method available. You are able to send "raw" commands to this method.
Function overview
All the methods listed in Function Reference are implemented.
Replacement methods
Some original methods do require a config or properties object as parameter. This API library also wraps some of these methods so you can use regular named parameters.
E.g. the method CreateSystemAdministrator has the signature
CreateSystemAdministrator(self, config, password)
The replacement method has the signature
CreateSystemAdministrator2(self, userName, fullName=None, password=None)
the config object is created as follows and then passed to CreateSystemAdministrator along with the password parameter.
config = json.dumps({"userName": userName, "fullName": fullName})
The available replacement methods are
SetComplianceConfiguration2(self, instanceID, globalRetentionTimeYears=None, adminEmailPreviewEnabled=None, legalHoldEnabled=None, logSuccessfulUserActivities = None)
SetIndexConfiguration2(self, instanceID, extensions)
SetStoreAutoCreateConfiguration2(self, instanceID, enabled=True, interval="none", sizeThreshold=None, numberOfMessagesThreshold=500000, baseDirectory=None)
CreateClientAccessServer2(self, serverName, port, thumbprint)
CreateInstance2(self, instanceID, instanceHost, startMode, baseDirectory, alias=None, displayName=None, debugLogEnabled="false", vssWriterEnabled="false")
CreateInstanceHost2(self, serverName, port, thumbprint, baseDirectory)
CreateSystemAdministrator2(self, userName, fullName=None, password=None)
UpdateClientAccessServerConfiguration2(self, serverName, port, thumbprint)
UpdateInstanceHostConfiguration2(self, serverName, port, thumbprint, baseDirectory)
UpdateSystemAdministratorConfiguration2(self, userName, fullName=None)
No replacement methods are currently available for the following methods
CreateProfile(self, instanceID, properties, raw="true")
RunTemporaryProfile(self, instanceID, properties, raw="true", autoHandleToken=None)
SetDirectoryServicesConfiguration(self, instanceID, config)
SetInstanceConfiguration(self, config)
Additional methods
There are additional methods available. Please see the source code for further details.