Package: graphish
Welcome to graphish documentation!_______ .______          ___      .______    __    __   __       _______. __    __  
 /  _____||   _  \        /   \     |   _  \  |  |  |  | |  |     /       ||  |  |  | 
|  |  __  |  |_)  |      /  ^  \    |  |_)  | |  |__|  | |  |    |   (----`|  |__|  | 
|  | |_ | |      /      /  /_\  \   |   ___/  |   __   | |  |     \   \    |   __   | 
|  |__| | |  |\  \----./  _____  \  |  |      |  |  |  | |  | .----)   |   |  |  |  | 
 \______| | _| `._____/__/     \__\ | _|      |__|  |__| |__| |_______/    |__|  |__| 
                                                                                      

A Python package to search & delete messages from mailboxes in Office 365 using Microsoft Graph APICurrent Features* Searching
    * Create new Search
    * Update a Search
    * Get Search Folder
    * Get Search messages
    * Delete Search
* Deleting
    * Delete a Message
* Mailbox Rules
    * List Mailbox Rules
* Users
    * Return a list of email addresses in your Azure AD Tenant
* MailFolder
    * Create MailFolder
    * Move message to a MailFolder
    * List messages in a MailFolderInstallationTo use, please install the package locally:InstallationLocally:bash git clone git@github.com:swimlane/graphish.git cd graphish pip install setup.pyOS X & Linux:pipinstallgraphishWindows:pipinstallgraphishUsageTo use, you will need to have created a new application in Azure AD.  Follow these instructions to obtain the appropriate secrets:https://docs.microsoft.com/en-us/graph/auth-register-app-v2Please also checkout this blog post aboutgraphishhttps://swimlane.com/blog/swimlane-open-sources-graphish/Additionally, if you would likegraphishto search all users within your Azure tenant you need to provideUser.Read.Allpermissions to your Azure AD application during registration.Once you have this information, then you can do the following:GraphConnectorTo usegraphishyou must first create aGraphConnectorobject that contains all your authentication information.  Once you have created this connector object then a user will provide this object as a mandatory parameter to other classes within this package.Here are the different ways to generate aGraphConnectorobject and are dependent on which authentication workflow method you have choose for your application.Delegated AuthenticationTo usegraphishwith delegated permissions and a username and password you will need to supply the clientId, clientSecret, tenantId, as well as your accounts username and password.By using the delegated authentication (Single-Page, Web Apps, Mobile & Native Apps - Grant Auth Flow) you can search your own mailbox by not passing auserPrincipalNameor if you would like to search another mailbox then provide theuserPrincipalName(e-mail address):Creating connector for your account using a (Single-Page, Web Apps, Mobile & Native Apps) authentication flow:fromgraphishimportGraphConnectorconnector=GraphConnector(clientId='14b8e5asd-c5a2-4ee7-af26-53461f121eed',# you applications clientIdclientSecret='OdhG1hXb*UB/ho]A?0ZCci13KMflsHDy',# your applications clientSecrettenantId='c1141d00-072f-1eb9-2526-12802571dd41',# your applications Azure Tenant IDuserPrincipalName='first.last@myorg.onmicrosoft.com',# the user's mailbox you want to searchpassword='somepassword'# password of your normal or admin account)Creating connector for another users mailbox using a (Single-Page, Web Apps, Mobile & Native Apps) authentication flow:fromgraphishimportGraphConnector# For legacy app grant flow provide a username and passwordconnector=GraphConnector(clientId='14b8e5asd-c5a2-4ee7-af26-53461f121eed',# you applications clientIdclientSecret='OdhG1hXb*UB/ho]A?0ZCci13KMflsHDy',# your applications clientSecrettenantId='c1141d00-072f-1eb9-2526-12802571dd41',# your applications Azure Tenant IDuserPrincipalName='first.last@myorg.onmicrosoft.com',# the user's mailbox you want to searchpassword='somepassword'# password of your normal or admin accountuserPrincipalName='some.account@myorg.onmicrosoft.com'# the user's mailbox you want to search)Application AuthenticationTo usegraphishwith application permissions you will need to supply the clientId, clientSecret, and tenantId.By using the application authentication (Client Credentials Grant Auth Flow) you can search a specific mailbox or ALL mailboxes.Creating a connector for your account using a service/daemon authentication flow:fromgraphishimportGraphConnector# For backend / client_credential auth flow just supply the followingconnector=GraphConnector(clientId='14b8e5asd-c5a2-4ee7-af26-53461f121eed',# you applications clientIdclientSecret='OdhG1hXb*UB/ho]A?0ZCci13KMflsHDy',# your applications clientSecrettenantId='c1141d00-072f-1eb9-2526-12802571dd41',# your applications Azure Tenant ID)Creating a connector for another users mailbox using a service/daemon authentication flow:fromgraphishimportGraphConnector# For backend / client_credential auth flow just supply the followingconnector=GraphConnector(clientId='14b8e5asd-c5a2-4ee7-af26-53461f121eed',# you applications clientIdclientSecret='OdhG1hXb*UB/ho]A?0ZCci13KMflsHDy',# your applications clientSecrettenantId='c1141d00-072f-1eb9-2526-12802571dd41',# your applications Azure Tenant IDscopes=['https://graph.microsoft.com/.default']# the scopes (default value of https://graph.microsoft.com/.default))Creating a new SearchOnce you have determined your appropriate authentication and have created aGraphConnectorobject, then you can create a newSearchObject.  Once you have yourSearchObject then you can create a new search, retrieve messages from your search, get search folders, update a search folder, or delete a search.  When you create a new search, this will create a hidden folder in the users mailbox (that the user is unable to see) and it will populate based on your search filterQuery.When you create (or instantiate) aSearchobject you can specify the scope of your search. There are three use-cases related to specifying a search:Provide a user principal name to theuserPrincipalNameparameter on theSearchclassProvide 'me' to theuserPrincipalNameparameter on theSearchclass when you are using username and password authentication workflowDEFAULT: Provide no value to theuserPrincipalNameparameter on theSearchclass.  This will pull in all users within your Azure AD via the ListUsers endpoint.NOTE: If using application authentication workflow, you can either pass in a single or list of  userPrincipalName's.  If you DO NOT pass in a userPrincipalName then Search will attempt to search all mailboxes in your Azure AD tenant!fromgraphishimportSearchsearch=Search(connector)new_search=search.create(searchFolderName='Phishing Search',sourceFolder='inbox',filterQuery="contains(subject, 'EXPIRES')")Getting messages from a SearchYou can retrieve messages identified during your search by using the same instance of your Search object and using themessagesmethod:# get all the messages in your search folderformessageinsearch.messages():print(message)# Returns all attributes from a messageprint(message['id'])# returns the message IDprint(message['headers'])# Returns the RFC822 headers of the messageGetting a list of mail foldersIf you are needing a list of mail folders in a mailbox you can use thefoldersmethod to retrieve them:# get a list of search folderssearch.folders()Getting a list of usersIf you are needing a list of all users within your search scope:# get a list of userssearch.userMoving a message to a folderIf you have performed a search and want to move a message to a mail folder, you can do so by doing the following:fromgraphishimportSearchfromgraphishimportGraphConnectorfromgraphishimportMailFolderconnector=GraphConnector(clientId='14b8e5asd-c5a2-4ee7-af26-53461f121eed',# you applications clientIdclientSecret='OdhG1hXb*UB/ho]A?0ZCci13KMflsHDy',# your applications clientSecrettenantId='c1141d00-072f-1eb9-2526-12802571dd41'# your applications Azure Tenant ID)search=Search(connector,userPrincipalName='some.account@myorg.onmicrosoft.com')new_search=search.create(searchFolderName='Phishing Search',sourceFolder='inbox',filterQuery="contains(subject, 'phishing')")messages=search.messages()formessageinmessages:print(message['internetMessageId'])print(message['fromAddress'])print(message['id'])mail_folder=MailFolder(connector,'some.account@myorg.onmicrosoft.com')moved_message=mail_folder.move_message(message['id'],'junkemail')print(moved_message)Creating a new MailFolderYou can also create a newMailFolderusing theMailFolderclass:fromgraphishimportMailFoldermail_folder=MailFolder(connector,'some.account@myorg.onmicrosoft.com')new_mail_folder=mail_folder.create('My Phishing Folder')['id']Updating a searchIf you wanted to make changes to a search performed you can update the search folder and individual criteria like the name of the search folder, the sourceFolder (root to search), or the filterQuery itself:# update your search folder property'ssearch.update(searchFolderName='Some Phishing Search',sourceFolder='inbox',filterQuery="contains(subject, 'EXPIRES!')")Deleting a searchYou can also delete a search performed by using thedeletemethod:# delete the current search foldersearch.delete()List Mailbox RulesAdditionally, you can list any mailbox rules:fromgraphishimportRulesrules=Rules(connector,userPrincipalName='some.account@myorg.onmicrosoft.com')print(rules.get())Additional ExamplesYou can find additional exampleshereRelease History1.0.0Initial release of graphish to PyPi1.3.0Added capabilities to get all users and to move messages to a specified mailfolderMetaJosh Rickard –@MSAdministrator–rickardja@live.comDistributed under the MIT license. SeeLICENSEfor more information.ContributingFork it (https://github.com/swimlane/graphish/fork)Create your feature branch (git checkout -b feature/fooBar)Commit your changes (git commit -am 'Add some fooBar')Push to the branch (git push origin feature/fooBar)Create a new Pull Request