Below is the API calls.
Use me for your own mailbox or the userID if another mailbox.
The below will return the child folders if you are looking for another folder rather than INBOX
https://graph.microsoft.com/v1.0/me/mailFolders/(FolderID)/childFolders
You can use ?%24skip=30 to move on down your folder list if large, url links for next are included in the returned message.
Then using the folder ID from above you then pull the emails from the folder.
https://graph.microsoft.com/v1.0/me/mailFolders/(FolderID)/messages
I then use the isRead (true or false) to see for new email. This will only return the first 10 items, but a URL is provided to pull the next 10 and so on. So you may have to do multiple pulls. I use mailbox rules to clean-up so I can get away with only one pull.
Try the explorer to test it out
Graph Explorer
Below is the flow to get your tokens and they refresh evrey 30mins. Unable to give credit to who wrote this as I cannot find it now. It was part of a presence flow that was upload. Just enter your tenant ID and client ID. Then put in the scope you require. On first inject you will get an URL which you need to enter with the code provide to give the auth.
[
{
"id": "40792ca0.843c24",
"type": "http request",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "",
"method": "POST",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 710,
"y": 160,
"wires": [
[
"44c485e1.fa8d2c",
"643ed329.5bdfec"
]
]
},
{
"id": "419648fb.f1a818",
"type": "inject",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "launch device code request",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 180,
"y": 160,
"wires": [
[
"427185e9.4132fc"
]
]
},
{
"id": "657e48c9.bcda48",
"type": "function",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "Set refresh_token",
"func": "flow.get('refresh_token', function(err, refresh_token) {\n if (err) {\n node.error(err, msg);\n } else {\n // initialise the counter to 0 if it doesn't exist already\n refresh_token = msg.payload.refresh_token;\n // store the value back\n flow.set('refresh_token',refresh_token, function(err) {\n if (err) {\n node.error(err, msg);\n } else {\n // make it part of the outgoing msg object\n msg.refresh_token = refresh_token;\n // send the message\n node.status({fill:\"green\",shape:\"dot\",text:`refresh_token: ${msg.refresh_token}`});\n node.send(msg);\n }\n });\n }\n});\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 990,
"y": 340,
"wires": [
[]
]
},
{
"id": "d1253feb.c9362",
"type": "function",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "Set access_token",
"func": "flow.get('access_token', function(err, access_token) {\n if (err) {\n node.error(err, msg);\n } else {\n // initialise the counter to 0 if it doesn't exist already\n access_token = msg.payload.access_token;\n // store the value back\n flow.set('access_token',access_token, function(err) {\n if (err) {\n node.error(err, msg);\n } else {\n // make it part of the outgoing msg object\n msg.access_token = access_token;\n // send the message\n node.status({fill:\"green\",shape:\"dot\",text:`access_token: ${msg.access_token}`});\n node.send(msg);\n }\n });\n }\n});\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 990,
"y": 300,
"wires": [
[]
]
},
{
"id": "44c485e1.fa8d2c",
"type": "function",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "Set device_code",
"func": "flow.get('device_code', function(err, refresh_token) {\n if (err) {\n node.error(err, msg);\n } else {\n // initialise the counter to 0 if it doesn't exist already\n device_code = msg.payload.device_code;\n // store the value back\n flow.set('device_code',device_code, function(err) {\n if (err) {\n node.error(err, msg);\n } else {\n // make it part of the outgoing msg object\n msg.device_code = device_code;\n // send the message\n node.status({fill:\"green\",shape:\"dot\",text:`device_code: ${msg.device_code}`});\n node.send(msg);\n }\n });\n }\n});\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 950,
"y": 160,
"wires": [
[]
]
},
{
"id": "648d5fe3.74d0b",
"type": "function",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "",
"func": "var context = flow.get(['tenant_id','client_id','scope','device_code']);\nvar tenant_id = context[0];\nvar client_id = context[1];\nvar scope = context[2];\nvar device_code = context[3];\n\nif(!device_code)\n{\n msg.delay = 5*1000;\n return [msg, null];\n}\n\nif(tenant_id && client_id && scope && device_code)\n{\n msg.url = \"https://login.microsoftonline.com/\"+tenant_id+\"/oauth2/v2.0/token\";\n msg.headers = { \"Content-Type\": \"application/x-www-form-urlencoded\"};\n msg.payload = {\n \"client_id\": client_id,\n \"grant_type\": \"urn:ietf:params:oauth:grant-type:device_code\",\n \"scope\": scope,\n \"code\": device_code\n }\n node.status({fill:\"green\",shape:\"dot\",text:`device_code: ${device_code.substring(0, 10)}`});\n return [null, msg];\n}\n",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 320,
"y": 320,
"wires": [
[
"ddaa0b36.e42108"
],
[
"1fc0a330.6fe22d"
]
]
},
{
"id": "ec8a6999.9abcd8",
"type": "inject",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 130,
"y": 320,
"wires": [
[
"648d5fe3.74d0b"
]
]
},
{
"id": "1fc0a330.6fe22d",
"type": "http request",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "",
"method": "POST",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 510,
"y": 320,
"wires": [
[
"d32c769a.1c42b8"
]
]
},
{
"id": "ba3c9093.320a7",
"type": "comment",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "Retrieve tokens ...",
"info": "... after login has been made in a browser",
"x": 130,
"y": 260,
"wires": []
},
{
"id": "d4b1dae2.c6c538",
"type": "comment",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "refresh tokens every 30 minutes",
"info": "",
"x": 170,
"y": 400,
"wires": []
},
{
"id": "396bdeb0.93db72",
"type": "inject",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "1800",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 130,
"y": 440,
"wires": [
[
"8739bad6.405738"
]
]
},
{
"id": "8739bad6.405738",
"type": "function",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "refresh request",
"func": "var context = flow.get(['tenant_id','client_id','scope','refresh_token']);\nvar tenant_id = context[0];\nvar client_id = context[1];\nvar scope = context[2];\nvar refresh_token = context[3];\n\nmsg.url = \"https://login.microsoftonline.com/\"+tenant_id+\"/oauth2/v2.0/token\"; \nmsg.headers = {\n \"Content-Type\": \"application/x-www-form-urlencoded\"\n};\nmsg.payload = {\n \"grant_type\": \"refresh_token\",\n \"client_id\": client_id,\n \"refresh_token\": `${refresh_token}`,\n \"scope\": scope\n\n};\n\nif(tenant_id && client_id && scope && refresh_token )\n return msg;\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 340,
"y": 440,
"wires": [
[
"1aafbb4a.e050b5"
]
]
},
{
"id": "1aafbb4a.e050b5",
"type": "http request",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "",
"method": "POST",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 550,
"y": 440,
"wires": [
[
"d32c769a.1c42b8"
]
]
},
{
"id": "b28b4494.18e868",
"type": "inject",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "change my values",
"props": [
{
"p": "scope",
"v": "Presence.Read offline_access Calendars.Read Calendars.Read.Shared Files.ReadWrite.All Mail.ReadWrite",
"vt": "str"
},
{
"p": "tenant_id",
"v": "",
"vt": "str"
},
{
"p": "client_id",
"v": "",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"x": 150,
"y": 100,
"wires": [
[
"4bb4827.9197c7c"
]
]
},
{
"id": "4bb4827.9197c7c",
"type": "function",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "prepare context",
"func": "flow.get('tenant_id', function(err, tenant_id) {\n if (err) {\n node.error(err, msg);\n } else {\n // store the value\n flow.set('tenant_id',msg.tenant_id, function(err) {\n if (err) {\n node.error(err, msg);\n } else {\n flow.get('scope', function(err, scope) {\n if (err) {\n node.error(err, msg);\n } else {\n // store the value\n flow.set('scope',msg.scope, function(err) {\n if (err) {\n node.error(err, msg);\n } else {\n flow.get('client_id', function(err, client_id) {\n if (err) {\n node.error(err, msg);\n } else {\n // store the value\n flow.set('client_id',msg.client_id, function(err) {\n if (err) {\n node.error(err, msg);\n } \n // no else here\n });\n }\n });\n }\n });\n }\n });\n node.status({fill:\"green\",shape:\"dot\",text:`OK: context prepared`});\n }\n });\n }\n});",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 380,
"y": 100,
"wires": [
[]
]
},
{
"id": "427185e9.4132fc",
"type": "function",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "prepare device code request",
"func": "msg.headers = { \"Content-Type\": \"application/x-www-form-urlencoded\"};\n\nvar context = flow.get(['tenant_id','client_id','scope']);\nvar tenant_id = context[0];\nvar client_id = context[1];\nvar scope = context[2];\nif(tenant_id && client_id && scope)\n{\n msg.url = \"https://login.microsoftonline.com/\"+tenant_id+\"/oauth2/v2.0/devicecode\"\n msg.payload = { \n \"client_id\": client_id,\n \"scope\": scope\n };\n node.status({fill:\"green\",shape:\"dot\",text:`Values passed on`});\n return msg;\n}\n\nnode.status({fill:\"red\",shape:\"dot\",text:`ERROR: context not prepared`});",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 460,
"y": 160,
"wires": [
[
"40792ca0.843c24"
]
]
},
{
"id": "ddaa0b36.e42108",
"type": "delay",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "",
"pauseType": "delayv",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"outputs": 1,
"x": 520,
"y": 240,
"wires": [
[
"648d5fe3.74d0b"
]
]
},
{
"id": "d32c769a.1c42b8",
"type": "function",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "",
"func": "var context = flow.get(['access_token','refresh_token']);\nvar access_token = context[0]; \nvar refresh_token = context[1]; \n\nif(msg.payload.hasOwnProperty('access_token') && \nmsg.payload.hasOwnProperty('refresh_token'))\n{\n flow.set('device_code',undefined);\n node.status({fill:\"green\",shape:\"dot\",text:`device now logged in, pass on message`});\n return [null, msg]; \n}\n\n\nif(access_token && refresh_token)\n{\n flow.set('device_code',undefined);\n node.status({fill:\"green\",shape:\"dot\",text:`device already logged in`});\n return [];\n}\n\nif(msg.payload.hasOwnProperty('error'))\n{\n if(msg.payload.error == \"authorization_pending\")\n {\n node.status({fill:\"blue\",shape:\"dot\",text:`Browser login pending`});\n msg.delay = 5*1000;\n return [msg, null]; \n }\n node.status({fill:\"red\",shape:\"dot\",text:`Error: ${msg.payload.error_description}`});\n return [];\n}\n",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 740,
"y": 320,
"wires": [
[
"ddaa0b36.e42108"
],
[
"d1253feb.c9362",
"657e48c9.bcda48"
]
]
},
{
"id": "643ed329.5bdfec",
"type": "debug",
"z": "7c76e545.92af9c",
"g": "8cd0bb2bd73e9d46",
"name": "Auth link and device code",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 980,
"y": 100,
"wires": []
}
]