Welcome to py-ews’s documentation!


    .______   ____    ____       ___________    __    ____   _______.
    |   _  \  \   \  /   /      |   ____\   \  /  \  /   /  /       |
    |  |_)  |  \   \/   / ______|  |__   \   \/    \/   /  |   (----`
    |   ___/    \_    _/ |______|   __|   \            /    \   \    
    |  |          |  |          |  |____   \    /\    / .----)   |   
    | _|          |__|          |_______|   \__/  \__/  |_______/    
                                                                 


    A Python package to interact with Exchange Web Services

py-ews is a cross platform python package to interact with both Exchange 2010 to 2019 on-premises and Exchange Online (Office 365).

This package will wrap all Exchange Web Service endpoints, but currently is focused on providing eDiscovery endpoints.

Features

py-ews has the following notable features in it’s current release:

  • Autodiscover support
  • Delegation support
  • Impersonation support
  • OAUth2 support
  • Retrieve all mailboxes that can be searched based on credentials provided
  • Search a list of (or single) mailboxes in your Exchange environment using all supported search attributes
  • Delete email items from mailboxes in your Exchange environment
  • Retrieve mailbox inbox rules for a specific account
  • Find additional hidden inbox rules for a specified account
  • Plus more supported endpoints

Currently this package supports the following endpoint’s:

Installation

OS X & Linux:

pip install py-ews

Windows:

pip install py-ews

Creating EWS Object

When instantiating the EWS class you will need to provide credentials which will be used for all methods within the EWS class.

from pyews import EWS

ews = EWS(
      'myaccount@company.com',
      'Password1234'
)

If you would like to use an alternative EWS URL then provide one using the ews_url parameter when instantiating the EWS class.

from pyews import EWS

ews = EWS(
      'myaccount@company.com',
      'Password1234',
      ews_url='https://outlook.office365.com/autodiscover/autodiscover.svc'
)

If you would like to specify a specific version of Exchange to use, you can provide that using the exchange_version parameter. By default pyews will attempt all Exchange versions as well as multiple static and generated EWS URLs.

Finally, if you would like to impersonate_as a specific user you must provide their primary SMTP address when instantiating the EWS class object:

from pyews import EWS

ews = EWS(
      'myaccount@company.com',
      'Password1234',
      impersonate_as='myotheraccount@company.com'
)

Exchange Search Multi-Threading

You can also specify multi_threading=True and when you search mailboxes we will use multi-threading to perform the search.

Using Provided Methods

Once you have instantiated the EWS class with your credentials, you will have access to pre-exposed methods for each endpoint. These methods are:

  • get_service_configuration
  • get_searchable_mailboxes
  • get_user_settings
  • resolve_names
  • execute_ews_search
  • execute_outlook_search
  • get_inbox_rules
  • get_hidden_inbox_rules
  • get_item
  • get_attachment
  • sync_folder_hierarchy
  • sync_folder_items
  • create_item
  • delete_item
  • search_and_delete_message
  • get_domain_settings
  • find_items
  • search_mailboxes_using_find_item
  • create_search_folder
  • find_search_folder
  • delete_search_folder

Access Classes Directly

In some cases you may want to skip using the EWS interface class and build your own wrapper around py-ews. To do this, you must first import the Authentication class and provide credential and other details before invoking a desired endpoint. Below is an example of this:

from pyews import Authentication, GetSearchableMailboxes

Authentication(
      'myaccount@company.com',
      'Password1234'
)

reference_id_list = []
for mailbox in GetSearchableMailboxes().run():
      reference_id_list.append(mailbox.get('reference_id'))
      print(mailbox)

As you can see, you must instantiate the Authentication class first before calling an endpoint. By the way, you can import all endpoints directly without using the EWS interface.

For more examples and usage, please refer to the individual class documentation

Release History

  • 1.0.0
    • Initial release of py-ews and it is still considered a work in progress
  • 2.0.0
    • Revamped logic and overhauled all endpoints and classes
  • 3.0.0
    • Refactored completely - this can be considered a new version

Meta

Josh Rickard – @MSAdministrator

Distributed under the MIT license. See LICENSE for more information.

Contributing

  1. Fork it (https://github.com/swimlane/pyews/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Commit your changes (git commit -am 'Add some fooBar')
  4. Push to the branch (git push origin feature/fooBar)
  5. Create a new Pull Request

Core

Core

The Core class is inherited by all other classes within py-ews. This class controls logging as well as parsing of EWS SOAP request responses.

class pyews.core.core.Core

The Core class inherits logging and defines required authentication details as well as parsing of results

camel_to_snake(s)
parse_response(soap_response, namespace_dict=None)

parse_response is standardized to parse all soap_responses from EWS requests

Args:
soap_response (BeautifulSoup): EWS SOAP response returned from the Base class namespace_dict (dict, optional): A dictionary of namespaces to process. Defaults to None.
Returns:
list: Returns a list of dictionaries containing parsed responses from EWS requests.

Authentication

The Authentication class is used to configure all communications with Exchange. Additionally, this class contains settings which are used when generating and making SOAP requests.

This class defines the authenication credentials, ews_url(s) to attempt, exchange versions, impersonation details, and more.

class pyews.core.authentication.Authentication

ExchangeVersion

This documentation provides details about the ExchangeVersion class within the pyews package.

class pyews.core.exchangeversion.ExchangeVersion(version)

Used to validate compatible Exchange Versions across multiple service endpoints

Examples:
To determine if a version number is a valid ExchangeVersion then would pass in the value when instantiating this object:
Args:
version (str): An Exchange Version number. Example: 15.20.5 = Exchange2016
API_VERSION_MAP = {8: {0: 'Exchange2007', 1: 'Exchange2007_SP1', 2: 'Exchange2007_SP1', 3: 'Exchange2007_SP1'}, 14: {0: 'Exchange2010', 1: 'Exchange2010_SP1', 2: 'Exchange2010_SP2', 3: 'Exchange2010_SP2'}, 15: {0: 'Exchange2013', 1: 'Exchange2016', 2: 'Exchange2019', 20: 'Exchange2016'}}
EXCHANGE_VERSIONS = ['Exchange2019', 'Exchange2016', 'Exchange2015', 'Exchange2013_SP1', 'Exchange2013', 'Exchange2010_SP2', 'Exchange2010_SP1', 'Exchange2010']
static valid_version(version)

Determines if a string version name is in list of accepted Exchange Versions

Args:
version (str): String used to determine if it is an acceptable Exchange Version
Returns:
bool: Returns either True or False if the passed in version is an acceptable Exchange Version

Endpoints

This documentation provides details about the set and generated API endpoints used within the pyews package.

class pyews.core.endpoints.Endpoints(domain=None)

Endpoints provides and generates endpoints to attempt EWS requests against.

get()

Endpoints

This documentation provides details about the available Exchange Web Services endpoints within the pyews package.

All endpoints inherit from either the Autodiscover or Operation classes. These classes make extensibility much easier and allows users of this package to define new endpoints easily.

AddDelegate

This documentation provides details about the AddDelegate class within the pyews package.

This class is used to add delegates to a provided mailbox.

class pyews.endpoint.adddelegate.AddDelegate(target_mailbox, delegate_to, inbox_permissions=None, calender_permissions=None, contacts_permissions=None)

Adds the delegate_to to the provided target_mailbox with specific permission sets.

Args:
target_mailbox (str): The mailbox in which permissions are added delegate_to (str): The account that the permissions are assocaited with inbox_permissions (str, optional): Mailbox permission set value. Defaults to None. calender_permissions (str, optional): Calendar permission set value. Defaults to None. contacts_permissions (str, optional): Contacts permission set value. Defaults to None.
RESULTS_KEY = 'Items'
soap()

ConvertId

This documentation provides details about the ConvertId class within the pyews package.

This class is used to convert item and folder ids from one format to another.

class pyews.endpoint.convertid.ConvertId(user, item_id, id_type, convert_to)

Takes a specific user, item_id, id_type, and the desired format to conver to as inputs.

Args:
user (str): The mailbox that the ID is associated with item_id (str): The item ID id_type (str): The Item ID type convert_to (str): The format to conver the Item ID to
Raises:
UknownValueError: One or more provided values is unknown
ID_FORMATS = ['EntryId', 'EwsId', 'EwsLegacyId', 'HexEntryId', 'OwaId', 'StoreId']
RESULTS_KEY = '@Id'
soap()

CreateFolder

This documentation provides details about the CreateFolder class within the pyews package.

This class is used to create folders (specifically focused on search folders) in the specified user mailbox.

class pyews.endpoint.createfolder.CreateFolder(search_string, search_folder=True, display_name='Search Folder', search_all_folders=True, base_folder='inbox', traversal='Deep')

Creates a Folder. Default behavior is to create a Search Folder (eDiscovery Search Folder)

Args:
search_string (str): A search string which is converted to a Search Filter search_folder (bool, optional): Creates a Search Folder. Defaults to True. display_name (str, optional): The display name of the search folder. Defaults to ‘Search Folder’. base_folder (str, optional): The base folder the search folder should look at. Defaults to ‘inbox’. traversal (str, optional): The traversal type. Options are Deep and Shallow. Defaults to ‘Deep’.
BASE_SHAPES = ['IdOnly', 'Default', 'AllProperties']
BODY_TYPES = ['Best', 'HTML', 'Text']
RESULTS_KEY = 'CreateFolderResponseMessage'
SEARCH_FILTERS = ['Contains', 'Excludes', 'Exists', 'IsEqualTo', 'IsNotEqualTo', 'IsGreaterThan', 'IsGreaterThanOrEqualTo', 'IsLessThan', 'IsLessThanOrEqualTo']
soap()

CreateItem

This documentation provides details about the CreateItem class within the pyews package.

This class is used to create items in a users mailbox.

class pyews.endpoint.createitem.CreateItem(type='message', message_disposition='SendAndSaveCopy', save_item_to='sentitems', **kwargs)

Creates an e-mail message

Args:
type (str, optional): The type of item to create. Defaults to ‘message’. message_disposition (str, optional): The action to take when the item is created. Defaults to ‘SendAndSaveCopy’. save_item_to (str, optional): Where to save the created e-mail message. Defaults to ‘sentitems’.
BODY_TYPES = ['Best', 'HTML', 'Text']
MESSAGE_DISPOSITION = ['SaveOnly', 'SendOnly', 'SendAndSaveCopy']
RESULTS_KEY = 'Items'
soap()

DeleteFolder

This documentation provides details about the DeleteFolder class within the pyews package.

This class is used to delete folders (specifically focused on search folders) from the specified user mailbox.

class pyews.endpoint.deletefolder.DeleteFolder(folder_id)
RESULTS_KEY = 'Folders'
soap()

DeleteItem

This documentation provides details about the DeleteItem class within the pyews package.

This class is used to delete items (typically mailbox items) from the specified user mailbox.

class pyews.endpoint.deleteitem.DeleteItem(item_id, delete_type='MoveToDeletedItems')

Deletes the provided Item ID from an Exchange store.

Args:
item_id (str): The Item ID to delete delete_type (str, optional): The delete type when deleting the item. Defaults to ‘MoveToDeletedItems’.
DELETE_TYPES = ['HardDelete', 'SoftDelete', 'MoveToDeletedItems']
soap()

ExecuteSearch

This documentation provides details about the ExecuteSearch class within the pyews package.

This class is used to execute a search as the authenticated user but acting like an Outlook mail client.

class pyews.endpoint.executesearch.ExecuteSearch(query, result_row_count='25', max_results_count='-1')

Executes a search as an Outlook client for the authenticated user.

Args:
query (str): The query to search for. result_row_count (str, optional): The row count of results. Defaults to ‘25’. max_results_count (str, optional): The max results count. -1 equals unlimited. Defaults to ‘-1’.
RESULTS_KEY = 'Items'
soap()

ExpandDL

This documentation provides details about the ExpandDL class within the pyews package.

This class is used to expand a provided distrubtion list / group.

class pyews.endpoint.expanddl.ExpandDL(user)

Expands the provided distribution list

Args:
user (str): The distribution list to expand
RESULTS_KEY = 'Items'
soap()

FindFolder

This documentation provides details about the FindFolder class within the pyews package.

This class is used to find (search) for a search folder in a mailbox.

class pyews.endpoint.findfolder.FindFolder(folder_id='searchfolders', traversal='Shallow')
BASE_SHAPES = ['IdOnly', 'Default', 'AllProperties']
BODY_TYPES = ['Best', 'HTML', 'Text']
RESULTS_KEY = 'Folders'
SEARCH_FILTERS = ['Contains', 'Excludes', 'Exists', 'IsEqualTo', 'IsNotEqualTo', 'IsGreaterThan', 'IsGreaterThanOrEqualTo', 'IsLessThan', 'IsLessThanOrEqualTo']
soap()

FindItem

This documentation provides details about the FindItem class within the pyews package.

This class is used to find (search) an item from a mailbox.

class pyews.endpoint.finditem.FindItem(query_string, distinguished_folder_name='inbox', base_shape='AllProperties', include_mime_content=True, body_type='Best', traversal='Shallow', reset_cache=False, return_deleted_items=True, return_highlight_terms=True)

Retrieves results from a query string

Args:
item_id (str): The item id you want to get information about. change_key (str, optional): The change key of the item. Defaults to None. base_shape (str, optional): The base shape of the returned item. Defaults to ‘AllProperties’. include_mime_content (bool, optional): Whether or not to include MIME content. Defaults to True. body_type (str, optional): The item body type. Defaults to ‘Best’.
BASE_SHAPES = ['IdOnly', 'Default', 'AllProperties']
BODY_TYPES = ['Best', 'HTML', 'Text']
RESULTS_KEY = 'Message'
soap()

GetAttachment

This documentation provides details about the GetAttachment class within the pyews package.

This class is used to retrieve an attachment object using a provided attachment id.

class pyews.endpoint.getattachment.GetAttachment(attachment_id)

Retrieves the provided attachment_id

Args:
attachment_id (str): The attachment_id to retrieve.
RESULTS_KEY = 'Attachments'
soap()

GetHiddenInboxRules

This documentation provides details about the GetHiddenInboxRules class within the pyews package.

This class is used to get hidden mailbox rules from the specified user mailbox.

class pyews.endpoint.gethiddeninboxrules.GetHiddenInboxRules

FindItem EWS Operation attempts to find hidden inbox rules based on ExtendedFieldURI properties.

RESULTS_KEY = 'Items'
soap()

GetInboxRules

This documentation provides details about the GetInboxRules class within the pyews package.

This class is used to get mailbox rules from the specified user mailbox.

class pyews.endpoint.getinboxrules.GetInboxRules(user=None)

Retrieves inbox rules for the authenticated or specified user.

Args:
user (str, optional): The user to retrieve inbox rules for. Defaults to authenticated user.
RESULTS_KEY = 'GetInboxRulesResponse'
soap()

GetItem

This documentation provides details about the GetItem class within the pyews package.

This class is used to retrieve an item from a mailbox.

class pyews.endpoint.getitem.GetItem(item_id, change_key=None, base_shape='AllProperties', include_mime_content=True, body_type='Best')

Retrieves details about a provided item id

Args:
item_id (str): The item id you want to get information about. change_key (str, optional): The change key of the item. Defaults to None. base_shape (str, optional): The base shape of the returned item. Defaults to ‘AllProperties’. include_mime_content (bool, optional): Whether or not to include MIME content. Defaults to True. body_type (str, optional): The item body type. Defaults to ‘Best’.
BASE_SHAPES = ['IdOnly', 'Default', 'AllProperties']
BODY_TYPES = ['Best', 'HTML', 'Text']
RESULTS_KEY = 'Items'
soap()

GetSearchableMailboxes

This documentation provides details about the GetSearchableMailboxes class within the pyews package.

This class is used to retrieve all searchable mailboxes that the user configuration has access to search.

class pyews.endpoint.getsearchablemailboxes.GetSearchableMailboxes(search_filter=None, expand_group_memberhip=True)

Retrieves all searchable mailboxes the authenticated user has access to search.

Args:
search_filter (str, optional): A search filter. Typically used to search specific distribution groups. Defaults to None. expand_group_memberhip (bool, optional): Whether or not to expand group memberships. Defaults to True.
RESULTS_KEY = 'SearchableMailbox'
soap()

GetServiceConfiguration

This documentation provides details about the GetServiceConfiguration class within the pyews package.

This class is used to retrieve one or more service configurations.

class pyews.endpoint.getserviceconfiguration.GetServiceConfiguration(configuration_name=None, acting_as=None)

Retrieves service configuration details. Default will attempt to retrieve them all.

Args:
configuration_name (list, optional): The name of one or more configuration items. Defaults to ‘MailTips’,’UnifiedMessagingConfiguration’,’ProtectionRules’. acting_as (str, optional): If provided, will attempt to make call using provided user. Defaults to None.
Raises:
UknownValueError: Unknown value was provided
CONFIGURATION_NAMES = ['MailTips', 'UnifiedMessagingConfiguration', 'ProtectionRules']
RESULTS_KEY = 'ServiceConfigurationResponseMessageType'
soap()

GetUserSettings

This documentation provides details about the GetUserSettings class within the pyews package.

This class is used to retrieve user settings.

class pyews.endpoint.getusersettings.GetUserSettings(user=None)

Retrieves the user settings for the authenticated or provided user.

Args:
user (str, optional): A user to retrieve user settings for. Defaults to None.
RESULTS_KEY = 'UserSettings'
soap()

ResolveNames

This documentation provides details about the ResolveNames class within the pyews package.

This class is used to resolve a mailbox email address to retrieve details about a user.

class pyews.endpoint.resolvenames.ResolveNames(user=None)

Resolves the authenticated or provided name

Args:
user (str, optional): A user to attempt to resolve. Defaults to None.
RESULTS_KEY = 'ResolutionSet'
soap()

SearchMailboxes

This documentation provides details about the SearchMailboxes class within the pyews package.

This class is used to search users mailboxes for a specific item.

class pyews.endpoint.searchmailboxes.SearchMailboxes(query, reference_id, search_scope='All')

Searches one or more reference id’s using the provided query and search_scope.

Args:
query (str): The Advanced Query Syntax (AQS) to search with. reference_id (list): One or more mailbox reference Id’s search_scope (str, optional): The search scope. Defaults to ‘All’.
Raises:
UknownValueError: The provided search scope is unknown.
RESULTS_KEY = 'SearchPreviewItem'
SEARCH_SCOPES = ['All', 'PrimaryOnly', 'ArchiveOnly']
soap()

SyncFolderHierarchy

This documentation provides details about the SyncFolderHierarchy class within the pyews package.

This class is used to retrieve a users mailbox folder hierarchy.

class pyews.endpoint.syncfolderhierarchy.SyncFolderHierarchy(well_known_folder_name=None)

Retrieve the authenticated users mailbox folder hierarchy.

Args:
well_known_folder_name (str, optional): The well known folder name. Defaults to all known folder names.
FOLDER_LIST = ['msgfolderroot', 'calendar', 'contacts', 'deleteditems', 'drafts', 'inbox', 'journal', 'notes', 'outbox', 'sentitems', 'tasks', 'junkemail', 'searchfolders', 'voicemail', 'recoverableitemsdeletions', 'recoverableitemsversions', 'recoverableitemspurges', 'recipientcache', 'quickcontacts', 'conversationhistory', 'todosearch', 'mycontacts', 'imcontactlist', 'peopleconnect', 'favorites']
RESULTS_KEY = 'Changes'
soap()

SyncFolderItems

This documentation provides details about the SyncFolderItems class within the pyews package.

This class is used to retrieve individual items from a users mailbox.

class pyews.endpoint.syncfolderitems.SyncFolderItems(folder_id, change_key=None)

Retrieves details about a provided folder id.

Args:
folder_id (str): The folder id to retrieve details about. change_key (str, optional): The version key of the folder id. Defaults to None.
FIELD_ACTION_TYPE_MAP = {'create': ['Item', 'Message', 'CalendarItem', 'Contact', 'DistributionList', 'MeetingMessage', 'MeetingRequest', 'MeetingResponse', 'MeetingCancellation', 'Task'], 'delete': ['ItemId'], 'readflagchange': ['ItemId', 'IsRead'], 'update': ['Item', 'Message', 'CalendarItem', 'Contact', 'DistributionList', 'MeetingMessage', 'MeetingRequest', 'MeetingResponse', 'MeetingCancellation', 'Task']}
FIELD_URI_PROPERTIES = ['folder:FolderId', 'folder:ParentFolderId', 'folder:DisplayName', 'folder:UnreadCount', 'folder:TotalCount', 'folder:ChildFolderCount', 'folder:FolderClass', 'folder:SearchParameters', 'folder:ManagedFolderInformation', 'folder:PermissionSet', 'folder:EffectiveRights', 'folder:SharingEffectiveRights', 'item:ItemId', 'item:ParentFolderId', 'item:ItemClass', 'item:MimeContent', 'item:Attachments', 'item:Subject', 'item:DateTimeReceived', 'item:Size', 'item:Categories', 'item:HasAttachments', 'item:Importance', 'item:InReplyTo', 'item:InternetMessageHeaders', 'item:IsAssociated', 'item:IsDraft', 'item:IsFromMe', 'item:IsResend', 'item:IsSubmitted', 'item:IsUnmodified', 'item:DateTimeSent', 'item:DateTimeCreated', 'item:Body', 'item:ResponseObjects', 'item:Sensitivity', 'item:ReminderDueBy', 'item:ReminderIsSet', 'item:ReminderNextTime', 'item:ReminderMinutesBeforeStart', 'item:DisplayTo', 'item:DisplayCc', 'item:Culture', 'item:EffectiveRights', 'item:LastModifiedName', 'item:LastModifiedTime', 'item:ConversationId', 'item:UniqueBody', 'item:Flag', 'item:StoreEntryId', 'item:InstanceKey', 'item:NormalizedBody', 'item:EntityExtractionResult', 'itemPolicyTag', 'item:ArchiveTag', 'item:RetentionDate', 'item:Preview', 'item:NextPredictedAction', 'item:GroupingAction', 'item:PredictedActionReasons', 'item:IsClutter', 'item:RightsManagementLicenseData', 'item:BlockStatus', 'item:HasBlockedImages', 'item:WebClientReadFormQueryString', 'item:WebClientEditFormQueryString', 'item:TextBody', 'item:IconIndex', 'item:MimeContentUTF8', 'message:ConversationIndex', 'message:ConversationTopic', 'message:InternetMessageId', 'message:IsRead', 'message:IsResponseRequested', 'message:IsReadReceiptRequested', 'message:IsDeliveryReceiptRequested', 'message:ReceivedBy', 'message:ReceivedRepresenting', 'message:References', 'message:ReplyTo', 'message:From', 'message:Sender', 'message:ToRecipients', 'message:CcRecipients', 'message:BccRecipients', 'message:ApprovalRequestData', 'message:VotingInformation', 'message:ReminderMessageData', 'meeting:AssociatedCalendarItemId', 'meeting:IsDelegated', 'meeting:IsOutOfDate', 'meeting:HasBeenProcessed', 'meeting:ResponseType', 'meeting:ProposedStart', 'meeting:PropsedEnd', 'meetingRequest:MeetingRequestType', 'meetingRequest:IntendedFreeBusyStatus', 'meetingRequest:ChangeHighlights', 'calendar:Start', 'calendar:End', 'calendar:OriginalStart', 'calendar:StartWallClock', 'calendar:EndWallClock', 'calendar:StartTimeZoneId', 'calendar:EndTimeZoneId', 'calendar:IsAllDayEvent', 'calendar:LegacyFreeBusyStatus', 'calendar:Location', 'calendar:When', 'calendar:IsMeeting', 'calendar:IsCancelled', 'calendar:IsRecurring', 'calendar:MeetingRequestWasSent', 'calendar:IsResponseRequested', 'calendar:CalendarItemType', 'calendar:MyResponseType', 'calendar:Organizer', 'calendar:RequiredAttendees', 'calendar:OptionalAttendees', 'calendar:Resources', 'calendar:ConflictingMeetingCount', 'calendar:AdjacentMeetingCount', 'calendar:ConflictingMeetings', 'calendar:AdjacentMeetings', 'calendar:Duration', 'calendar:TimeZone', 'calendar:AppointmentReplyTime', 'calendar:AppointmentSequenceNumber', 'calendar:AppointmentState', 'calendar:Recurrence', 'calendar:FirstOccurrence', 'calendar:LastOccurrence', 'calendar:ModifiedOccurrences', 'calendar:DeletedOccurrences', 'calendar:MeetingTimeZone', 'calendar:ConferenceType', 'calendar:AllowNewTimeProposal', 'calendar:IsOnlineMeeting', 'calendar:MeetingWorkspaceUrl', 'calendar:NetShowUrl', 'calendar:UID', 'calendar:RecurrenceId', 'calendar:DateTimeStamp', 'calendar:StartTimeZone', 'calendar:EndTimeZone', 'calendar:JoinOnlineMeetingUrl', 'calendar:OnlineMeetingSettings', 'calendar:IsOrganizer', 'task:ActualWork', 'task:AssignedTime', 'task:BillingInformation', 'task:ChangeCount', 'task:Companies', 'task:CompleteDate', 'task:Contacts', 'task:DelegationState', 'task:Delegator', 'task:DueDate', 'task:IsAssignmentEditable', 'task:IsComplete', 'task:IsRecurring', 'task:IsTeamTask', 'task:Mileage', 'task:Owner', 'task:PercentComplete', 'task:Recurrence', 'task:StartDate', 'task:Status', 'task:StatusDescription', 'task:TotalWork', 'contacts:Alias', 'contacts:AssistantName', 'contacts:Birthday', 'contacts:BusinessHomePage', 'contacts:Children', 'contacts:Companies', 'contacts:CompanyName', 'contacts:CompleteName', 'contacts:ContactSource', 'contacts:Culture', 'contacts:Department', 'contacts:DisplayName', 'contacts:DirectoryId', 'contacts:DirectReports', 'contacts:EmailAddresses', 'contacts:FileAs', 'contacts:FileAsMapping', 'contacts:Generation', 'contacts:GivenName', 'contacts:ImAddresses', 'contacts:Initials', 'contacts:JobTitle', 'contacts:Manager', 'contacts:ManagerMailbox', 'contacts:MiddleName', 'contacts:Mileage', 'contacts:MSExchangeCertificate', 'contacts:Nickname', 'contacts:Notes', 'contacts:OfficeLocation', 'contacts:PhoneNumbers', 'contacts:PhoneticFullName', 'contacts:PhoneticFirstName', 'contacts:PhoneticLastName', 'contacts:Photo', 'contacts:PhysicalAddresses', 'contacts:PostalAddressIndex', 'contacts:Profession', 'contacts:SpouseName', 'contacts:Surname', 'contacts:WeddingAnniversary', 'contacts:UserSMIMECertificate', 'contacts:HasPicture', 'distributionlist:Members', 'postitem:PostedTime', 'conversation:ConversationId', 'conversation:ConversationTopic', 'conversation:UniqueRecipients', 'conversation:GlobalUniqueRecipients', 'conversation:UniqueUnreadSenders', 'conversation:GlobalUniqueUnreadSenders', 'conversation:UniqueSenders', 'conversation:GlobalUniqueSenders', 'conversation:LastDeliveryTime', 'conversation:GlobalLastDeliveryTime', 'conversation:Categories', 'conversation:GlobalCategories', 'conversation:FlagStatus', 'conversation:GlobalFlagStatus', 'conversation:HasAttachments', 'conversation:GlobalHasAttachments', 'conversation:HasIrm', 'conversation:GlobalHasIrm', 'conversation:MessageCount', 'conversation:GlobalMessageCount', 'conversation:UnreadCount', 'conversation:GlobalUnreadCount', 'conversation:Size', 'conversation:GlobalSize', 'conversation:ItemClasses', 'conversation:GlobalItemClasses', 'conversation:Importance', 'conversation:GlobalImportance', 'conversation:ItemIds', 'conversation:GlobalItemIds', 'conversation:LastModifiedTime', 'conversation:InstanceKey', 'conversation:Preview', 'conversation:GlobalParentFolderId', 'conversation:NextPredictedAction', 'conversation:GroupingAction', 'conversation:IconIndex', 'conversation:GlobalIconIndex', 'conversation:DraftItemIds', 'conversation:HasClutter', 'persona:PersonaId', 'persona:PersonaType', 'persona:GivenName', 'persona:CompanyName', 'persona:Surname', 'persona:DisplayName', 'persona:EmailAddress', 'persona:FileAs', 'persona:HomeCity', 'persona:CreationTime', 'persona:RelevanceScore', 'persona:WorkCity', 'persona:PersonaObjectStatus', 'persona:FileAsId', 'persona:DisplayNamePrefix', 'persona:YomiCompanyName', 'persona:YomiFirstName', 'persona:YomiLastName', 'persona:Title', 'persona:EmailAddresses', 'persona:PhoneNumber', 'persona:ImAddress', 'persona:ImAddresses', 'persona:ImAddresses2', 'persona:ImAddresses3', 'persona:FolderIds', 'persona:Attributions', 'persona:DisplayNames', 'persona:Initials', 'persona:FileAses', 'persona:FileAsIds', 'persona:DisplayNamePrefixes', 'persona:GivenNames', 'persona:MiddleNames', 'persona:Surnames', 'persona:Generations', 'persona:Nicknames', 'persona:YomiCompanyNames', 'persona:YomiFirstNames', 'persona:YomiLastNames', 'persona:BusinessPhoneNumbers', 'persona:BusinessPhoneNumbers2', 'persona:HomePhones', 'persona:HomePhones2', 'persona:MobilePhones', 'persona:MobilePhones2', 'persona:AssistantPhoneNumbers', 'persona:CallbackPhones', 'persona:CarPhones', 'persona:HomeFaxes', 'persona:OrganizationMainPhones', 'persona:OtherFaxes', 'persona:OtherTelephones', 'persona:OtherPhones2', 'persona:Pagers', 'persona:RadioPhones', 'persona:TelexNumbers', 'persona:WorkFaxes', 'persona:Emails1', 'persona:Emails2', 'persona:Emails3', 'persona:BusinessHomePages', 'persona:School', 'persona:PersonalHomePages', 'persona:OfficeLocations', 'persona:BusinessAddresses', 'persona:HomeAddresses', 'persona:OtherAddresses', 'persona:Titles', 'persona:Departments', 'persona:CompanyNames', 'persona:Managers', 'persona:AssistantNames', 'persona:Professions', 'persona:SpouseNames', 'persona:Hobbies', 'persona:WeddingAnniversaries', 'persona:Birthdays', 'persona:Children', 'persona:Locations', 'persona:ExtendedProperties', 'persona:PostalAddress', 'persona:Bodies']
RESULTS_KEY = 'Changes'
soap()

Service Classes

The Service sub-package defines the structure and ultimately makes it easier to build SOAP requests for all classes inherited from these modules.

All endpoints inherit from either the Autodiscover or Operation classes. These classes make extensibility much easier and allows users of this package to define new endpoints easily.

Autodiscover

The Autodiscover class is used by any endpoints that want to use the Microsoft Exchange Autodiscover service.

This class defines the SOAP Envelope, namespaces, headers, and body definitions for any class that inherits from it.

Autodiscover class inherits from the Base class and defines namespaces, headers, and body of an Autodiscover SOAP request

pyews.service.autodiscover.Autodiscover.raw_xml
pyews.service.autodiscover.Autodiscover.to

Base

The Base class is used by both the Autodiscover and Operation classes. Each of these classes inherit from this class which defines static values for namespaces and other elements using the ElementMaker factory pattern.

This class defines the SOAP Envelope, namespaces, headers, and body definitions for Autodiscover and Operation classes.

Additionally, the Base class performs all HTTP requests and response validation.

The Base class is used by all endpoints and network communications. It defines the base structure of all namespaces. It is inherited by the Autodiscover & Operation classes

pyews.service.base.Base.raw_xml

Operation

The Operation class is used by all EWS Operations except ones inherited by from Autodiscover.

This class defines the SOAP Envelope, namespaces, headers, and body definitions for any class that inherits from it.

Operation class inherits from the Base class and defines namespaces, headers, and body of EWS Operation SOAP request

pyews.service.operation.Operation.raw_xml

Adding Additional EWS Service Endpoints

As I stated above I will continue to add additional EWS Service Endpoints, but I wanted to share documentation on how to add your own support for additional service endpoints.

All endpoints inherit from either :doc:autodiscover or :doc:operation classes. In order to define a new endpoint you will need to import one of these classes.

from pyews.service import Operation

Once you have imported the appropriate class (typically this will be Operation) you will then create a new class and inherit from it. In this example I will demonstrate how to build a endpoint for the GetAppManifests operation:

from pyews.service import Operation

class GetAppManifests(Operation):

    def soap(self):
        pass

In order to inherit from Operation you must define the class name (which should be the name of the EWS operation) and a single method called soap.

The soap method will return the Body of a SOAP request using the provided elements.

  • M_NAMESPACE
  • T_NAMESPACE
  • A_NAMESPACE
  • WSA_NAMESPACE

By far the most common namespaces you will use wil be the M_NAMESPACE and T_NAMESPACE properties.

If we look at the example SOAP requst on this page you will see this:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types"
               xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages">
   <soap:Header>
      <t:RequestServerVersion Version="Exchange2013_SP1" />
      <t:MailboxCulture>en-US</t:MailboxCulture>
      <t:TimeZoneContext>
         <t:TimeZoneDefinition Id="GMT Standard Time"/>
      </t:TimeZoneContext>
   </soap:Header>
   <soap:Body >
      <m:GetAppManifests>
        <m:ApiVersionSupported>1.1</m:ApiVersionSupported>
        <m:SchemaVersionSupported>1.1</m:SchemaVersionSupported>
      </m:GetAppManifests>
   </soap:Body>
</soap:Envelope>

We will only worry about this portion of the XML SOAP request. All other data is managed by the inherited classes:

<m:GetAppManifests>
    <m:ApiVersionSupported>1.1</m:ApiVersionSupported>
    <m:SchemaVersionSupported>1.1</m:SchemaVersionSupported>
</m:GetAppManifests>

To define this using the provided namespaces will use the provided namespace attributes (e.g. m: or t:) and build our return object.

This means that our GetAppManifests class and soap method will look like this:

from pyews.service import Operation

class GetAppManifests(Operation):

    def soap(self):
        return self.M_NAMESPACE.GetAppManifests(
            self.M_NAMESPACE.ApiVersionSupported('1.1'),
            self.M_NAMESPACE.SchemaVersionSupported('1.1')
        )

That’s it! Seriously, pretty easy huh?

Additional details

If you see a SOAP request element on Microsoft’s site that looks like this:

<t:AlternateId Format="EwsId" Id="AAMkAGZhN2IxYTA0LWNiNzItN=" Mailbox="user1@example.com"/>

Then using our namespaces you would write this as:

self.T_NAMESPACE.AlternateId(Format="EwsId", Id="AAMkAGZhN2IxYTA0LWNiNzItN=", Mailbox="user1@example.com")
Running your class

Now that we have our newly defined endpoint we can instantiate it and then just call the run method.

from pyews import Authentication
from getappmanifests import GetAppManifests

Authentication('username', 'password')

print(GetAppManifests().run())

And we’re done! I hope this helps and if you have any feedback or questions please open a pull requst or an issue.

Utilities

Exceptions

This documentation provides details about Exceptions defined within the pyews package.

Raised when the provided value is unkown or is not in a specified list or dictionary map

pyews.utils.exceptions.UknownValueError.args

Logger

This documentation provides details about the Logger class within the pyews package.

type(object_or_name, bases, dict) type(object) -> the object’s type type(name, bases, dict) -> a new type