import argparse | |
from datetime import datetime | |
from getpass import getpass | |
import requests | |
AAD_GRAPH_SERVICE = "https://graph.microsoft.com" | |
AAD_TENANT = "<tenant>.onmicrosoft.com" | |
AAD_CLIENT_ID = "<app ID>" | |
class MicrosoftGraphClient(): | |
def __init__(self): | |
self._aad_client_secret = getpass("Client Secret for {}:".format(AAD_CLIENT_ID)) | |
data = { | |
"client_id": AAD_CLIENT_ID, | |
"scope": "https://graph.microsoft.com/.default", | |
"client_secret": self._aad_client_secret, | |
"grant_type": "client_credentials", | |
} | |
url = "https://login.microsoftonline.com/{}/oauth2/v2.0/token".format(AAD_TENANT) | |
self._session = requests.Session() | |
r = self._session.post(url, data=data) | |
if r.status_code == 200: | |
self._token = r.json()['access_token'] | |
else: | |
raise Exception("Failed to get OAuth Token: {}".format(r.json())) | |
def _get(self, url, params={}, header={}): | |
header['Authorization'] = "Bearer {}".format(self._token) | |
return self._session.get(url, params=params, headers=header) | |
def _get_values(self, endpoint, params={}): | |
url = "{}{}".format(AAD_GRAPH_SERVICE, endpoint) | |
r = self._get(url, params) | |
if r.status_code != 200: | |
raise Exception("Status code {} returned error: {}".format(r.status_code, r.json())) | |
total_count = 0 | |
while True: | |
count = len(r.json()['value']) | |
total_count = total_count + count | |
print("Processing {}/{}".format(count, total_count)) | |
yield from r.json()['value'] | |
if '@odata.nextLink' in r.json().keys(): | |
url = r.json()['@odata.nextLink'] | |
r = self._get(url) | |
else: | |
break | |
def _save_value(self, endpoint, filename): | |
r = self._get(endpoint) | |
if r.status_code != 200: | |
raise Exception("Status code {} returned error: {}".format(r.status_code, r.json())) | |
with open(filename, 'wb') as f: | |
f.write(r.content) | |
def download_eml(self, upn, subject): | |
params = { | |
"$select": "id,receivedDateTime,from,subject", | |
"$filter": "contains(subject,'{}')".format(subject), | |
} | |
for r in self._get_values("/v1.0/users/{}/messages".format(upn), params=params): | |
print(r) | |
dt = datetime.strptime(r['receivedDateTime'], "%Y-%m-%dT%H:%M:%SZ") | |
r = self._save_value( | |
"https://graph.microsoft.com/beta/users/{}/messages/{}/$value".format(upn, r['id']), | |
"{}-{}.eml".format(upn, dt.strftime("%Y-%m-%d_%H_%M_%S")) | |
) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description='Download .eml message content from the Microsoft Graph API.') | |
parser.add_argument( | |
'upn', | |
type=str, | |
help="The mailbox to search (usually the user's email address)" | |
) | |
parser.add_argument( | |
'subject', | |
type=str, | |
help="The subject to search for (can be partial)" | |
) | |
args = parser.parse_args() | |
client = MicrosoftGraphClient() | |
client.download_eml(args.upn, args.subject) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment