In my app i am trying to get the mail boxes of all the users registered in my users in azure portal using graph api and this is my code:
import React, { useState } from "react";
import { PublicClientApplication } from "@azure/msal-browser";
import { msalConfig } from "./msalConfig";
import axios from "axios";
const GraphApiTest = () => {
const [inboxEmails, setInboxEmails] = useState([]);
const [sentEmails, setSentEmails] = useState([]);
const msalInstance = new PublicClientApplication(msalConfig);
const loginAndFetchEmails = async () => {
try {
await msalInstance.initialize();
const accounts = msalInstance.getAllAccounts();
if (accounts.length === 0) {
// No logged-in user, perform login
await msalInstance.loginPopup({
scopes: [
"Mail.Read",
"Mail.Send",
"User.Read",
"User.Read.All",
"User-Mail.ReadWrite.All",
"Mail.ReadWrite.Shared",
"MailboxSettings.Read",
"Mail.Read.Shared",
], // Required scopes
});
}
const account = msalInstance.getAllAccounts()[0]; // Use the first account
let tokenResponse;
try {
// Attempt to acquire token silently
tokenResponse = await msalInstance.acquireTokenSilent({
account,
scopes: [
"Mail.Read",
"Mail.Send",
"User.Read",
"User.Read.All",
"User-Mail.ReadWrite.All",
"Mail.ReadWrite.Shared",
"MailboxSettings.Read",
"Mail.Read.Shared",
], // Required scopes
});
} catch (silentError) {
// Fallback to interactive login if silent acquisition fails
console.warn("Silent token acquisition failed, fallback to popup.");
tokenResponse = await msalInstance.acquireTokenPopup({
account,
scopes: [
"Mail.Read",
"Mail.Send",
"User.Read",
"User.Read.All",
"User-Mail.ReadWrite.All",
"Mail.ReadWrite.Shared",
"MailboxSettings.Read",
"Mail.Read.Shared",
], // Required scopes
});
}
const accessToken = tokenResponse.accessToken;
console.log("Access Token acquired:", accessToken);
// Fetch received emails (Inbox)
const inboxResponse = await axios.get(
"https://graph.microsoft.com/v1.0/users/example@visionx060.onmicrosoft.com/mailFolders('inbox')/messages",
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
// Fetch sent emails
const sentResponse = await axios.get(
"https://graph.microsoft.com/v1.0/users/example@visionx060.onmicrosoft.com/mailFolders('sentitems')/messages",
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
// Update state with emails
setInboxEmails(inboxResponse.data.value);
setSentEmails(sentResponse.data.value); // Sent emails
console.log("Sent Emails:", sentResponse.data.value);
} catch (error) {
console.error("Error during login or fetching emails:", error);
if (error.response) {
console.error("Response error:", error.response.data);
}
}
};
return (
<div>
<button onClick={loginAndFetchEmails}>Fetch Emails via Outlook</button>
<h2>Inbox Emails</h2>
<ul>
{inboxEmails.map((email) => (
<li key={email.id}>
<strong>{email.subject}</strong> from{" "}
{email.sender?.emailAddress?.address}
</li>
))}
</ul>
<h2>Sent Emails</h2>
<ul>
{sentEmails.map((email) => (
<li key={email.id}>
<strong>{email.subject}</strong> to{" "}
{email.toRecipients
.map((recipient) => recipient.emailAddress.address)
.join(", ")}
</li>
))}
</ul>
</div>
);
};
export default GraphApiTest;
export const msalConfig = {
auth: {
clientId: "my client id",
authority: "https://login.microsoftonline.com/<tenant-id>",
redirectUri: "http://localhost:3000", // Adjust as per your app
},
};
I have admin account and i granted following permissions in azure for this app: permissions screenshot
Still i am getting this window when a user other than admin try to fetch the mailbox of other users: the issue with user login
while the admin can get the other users mailbox without any problem. I want the same for other users too that they can get the other users mailboxes too.
Initially, I too got same error when an non-admin user tried to access mails of other user in delegated scenario without shared access:
In delegated scenarios, app can access mailboxes or resources for which the signed-in user has permissions, such as their own mailbox, shared mailboxes, or mailboxes that the user has explicitly granted access to (via delegation).
To allow non-admin users to access other users' mailboxes without needing delegation or sharing, you need to switch to application permissions and use the client credentials flow.
In my case, I registered one application and granted Mail.Read
permission of Application type with consent as below:
Now, I created one Node.js backend server project and installed dependencies in it with below commands:
mkdir email-fetcher-backend
cd email-fetcher-backend
npm init -y
npm install express axios body-parser dotenv
Later, I added below code files to store credentials and fetch emails with token generated using client credentials flow:
.env:
TENANT_ID=tenantId
CLIENT_ID=appId
CLIENT_SECRET=secret_value
server.js:
const express = require('express');
const axios = require('axios');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
const port = 5000;
const tenantId = process.env.TENANT_ID;
const clientId = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;
const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
// Fetch Access Token using Client Credentials Flow
const getAccessToken = async () => {
try {
const response = await axios.post(tokenUrl, new URLSearchParams({
client_id: clientId,
client_secret: clientSecret,
scope: 'https://graph.microsoft.com/.default',
grant_type: 'client_credentials',
}));
return response.data.access_token;
} catch (error) {
console.error('Error getting access token:', error);
throw new Error('Unable to get access token.');
}
};
// Fetch Emails (Inbox and Sent Items) from Microsoft Graph
app.get('/emails', async (req, res) => {
try {
const accessToken = await getAccessToken();
// Fetch inbox emails
const inboxResponse = await axios.get(
'https://graph.microsoft.com/v1.0/users/sri@xxxxxxxx.onmicrosoft.com/mailFolders/inbox/messages',
{ headers: { Authorization: `Bearer ${accessToken}` } }
);
// Fetch sent items emails
const sentResponse = await axios.get(
'https://graph.microsoft.com/v1.0/users/sri@xxxxxxxxx.onmicrosoft.com/mailFolders/sentitems/messages',
{ headers: { Authorization: `Bearer ${accessToken}` } }
);
// Format inbox emails as per the required format
const inboxEmails = inboxResponse.data.value.map(email => ({
subject: email.subject,
sender: email.sender.emailAddress.address,
}));
// Format sent emails as per the required format
const sentEmails = sentResponse.data.value.map(email => ({
subject: email.subject,
to: email.toRecipients.map(recipient => recipient.emailAddress.address).join(", "),
}));
// Send the formatted data back to the frontend
res.json({
inbox: inboxEmails,
sent: sentEmails,
});
} catch (err) {
console.error('Error fetching emails:', err);
res.status(500).send('Failed to fetch emails.');
}
});
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});
When I run the server with node server.js
command and visited http://localhost:5000/emails in browser, I got mails successfully like this:
Reference: