Configure Email with Microsoft Graph
Microsoft Graph is a method of email processing available for those using Office 365. Graph leverages your O365 setup to support inbound and outbound email processing.
For inbound email, Microsoft Graph checks only for unread emails. Emails that have been marked Read are not received. For this reason, it's best to use Graph with an inbound email account that is used only for this purpose, to avoid new emails being marked as Read.
Configure Microsoft Entra ID
First, you need to register your Agiloft system with Entra, formerly called Azure. As you follow the steps, you can also refer to Microsoft's setup instructions if any of the options you see differ from those described here.
The setup varies depending on whether you use the device code flow or the client code flow. For more information about these options, see Microsoft's documentation.
First, set up the application in Entra:
- Sign in to the Entra portal with the appropriate organization account.
- If your account has access to multiple tenants, select your account in the upper right corner and set your session to the appropriate AD tenant. For more information about tenants, see Microsoft's tenant documentation.
- Go to Identity > Applications > App registrations and select New registration.
- Enter a name for the registration. For example, you might name your registration " Agiloft Application for Graph."
- Select an option for who can use the application. This choice depends on how you use Entra. If you created an Entra account and tenant only for this purpose, select "Accounts in this organizational directory only."
- Leave the default Redirect URI settings.
- Click Register. The portal automatically directs you to the overview page for the Agiloft application.
- Copy the Application (client) ID and Directory (tenant) ID from the overview page. Store these in a note so you can copy them later.
- If you plan to use client code flow, you must also grant admin consent and generate a client secret:
- Click API Permissions in the sidebar and then click Grant admin consent. In the confirmation window, click Yes.
- Click Certificates & secrets in the sidebar.
- Click Add a new certificate or secret.
- Click New client secret.
- Enter a name, select the longest available expiration date, and then click Add. When the secret does expire, you'll need to repeat these setup steps to update your configuration with the new value.
- Copy the client secret Value when it appears, and store it in a note so you can refer to it later. You won't be able to access it after this point.
At this point, you need to configure either the device code flow or the client code flow. For more information about these options, see Microsoft's documentation.
Configure Client Code Flow
Before proceeding, you need to grant permission for your accounts to access your new application.
- In Entra, return to Home, go to Identity > Applications > Enterprise applications, and copy the Object ID to the same note you used earlier in the setup.
- Follow Microsoft's instructions to connect to Exchange Online PowerShell. Note that -UserPrincipalName must be an admin for the organization.
- Execute the following commands, using your application's values to substitute OBJECT_ID, CLIENT_ID, and TENANT_ID, and using the inbound and outbound email addresses in place of INBOUND_EMAIL and OUTBOUND_EMAIL:
$APPID = CLIENT_ID $OBJECTID = OBJECT_ID $DISPLAYNAME = 'Agiloft' $SVCINBOUND = INBOUND_EMAIL $SVCOUTBOUND = OUTBOUND_EMAIL $SVCINBOUNDALIAS = (Get-Mailbox -Anr $SVCINBOUND ).Alias $SVCOUTBOUNDALIAS = (Get-Mailbox -Anr $SVCOUTBOUND ).Alias New-ServicePrincipal -AppId $APPID -ObjectId $OBJECTID -DisplayName "Agiloft Graph Email" New-ManagementScope -Name "Agiloft Email Outbound" -RecipientRestrictionFilter "Alias -eq '$SVCOUTBOUNDALIAS'" New-ManagementRoleAssignment -Name "Agiloft Email Outbound Assignment" -App $APPID -Role "Application Mail.Send" -CustomResourceScope "Agiloft Email Outbound" New-ManagementScope -Name "Agiloft Email Inbound" -RecipientRestrictionFilter "Alias -eq '$SVCINBOUNDALIAS'" New-ManagementRoleAssignment -Name "Agiloft Email Inbound Assignment" -App $APPID -Role "Application Mail.ReadWrite" -CustomResourceScope "Agiloft Email inbound"
- If there are multiple Inbound accounts you can repeat the following lines for each extra account:
$SVCINBOUND = INBOUND_EMAIL $SVCINBOUNDALIAS = (Get-Mailbox -Anr $SVCINBOUND ).Alias New-ManagementScope -Name "Agiloft Email Inbound" -RecipientRestrictionFilter "Alias -eq '$SVCINBOUNDALIAS'" New-ManagementRoleAssignment -Name "Agiloft Email Inbound Assignment" -App $APPID -Role "Application Mail.ReadWrite" -CustomResourceScope "Agiloft Email inbound"
- Once complete, only the accounts targeted in the New Management Scopes will be able to make use of the permissions defined in the new ManagementRoleAssignment. Mail.Send is used for outbound email and Mail.ReadWrite is used for inbound email, as Write permission is required for Agiloft to mark items as Read.
Client Code Flow for Outbound Email
Now, you're ready to configure client code flow for outbound mail:
- Copy and paste the following code into a text editor:
#main setting and auth mail.smtp.auth.mechanisms=XOAUTH2 mail.agiloft.smtp.auth_flow=skip #Extended logging for troubleshooting mail.agiloft.smtp.trace=false mail.agiloft.smtp.tenant.id=e82****************2f29 mail.agiloft.smtp.client.id=de8*****************693fe #DO NOT specify in case the refresh token long live time is undefined! #mail.agiloft.smtp.refresh-token.llt= # authorization request mail.agiloft.smtp.device-auth-request.url=https://login.microsoftonline.com/${mail.agiloft.smtp.tenant.id}/oauth2/v2.0/token mail.agiloft.smtp.device-auth-request.payload.1=client_id=${mail.agiloft.smtp.client.id} mail.agiloft.smtp.device-auth-request.payload.2=scope=https://graph.microsoft.com/.default mail.agiloft.smtp.device-auth-request.payload.3=client_secret=ryK8****** mail.agiloft.smtp.device-auth-request.payload.4=grant_type=client_credentials mail.agiloft.smtp.device-auth-request.response.user_code.name=code #device access token request mail.agiloft.smtp.device-token.url=https://login.microsoftonline.com/${mail.agiloft.smtp.tenant.id}/oauth2/v2.0/token mail.agiloft.smtp.device-token.payload.1=client_id=${mail.agiloft.smtp.client.id} mail.agiloft.smtp.device-token.payload.2=scope=https://graph.microsoft.com/.default mail.agiloft.smtp.device-token.payload.3=client_secret=ryK8****** mail.agiloft.smtp.device-token.payload.4=grant_type=client_credentials mail.agiloft.smtp.device-token.response.access_token.name=access_token mail.agiloft.smtp.device-token.response.expire.name=expires_in #new token and refresh token mail.agiloft.smtp.device-token-refresh.url=https://login.microsoftonline.com/${mail.agiloft.smtp.tenant.id}/oauth2/v2.0/token mail.agiloft.smtp.device-token-refresh.payload.1=client_id=${mail.agiloft.smtp.client.id} mail.agiloft.smtp.device-token-refresh.payload.2=scope=https://graph.microsoft.com/.default mail.agiloft.smtp.device-token-refresh.payload.3=client_secret=ryK8****** mail.agiloft.smtp.device-token-refresh.payload.4=grant_type=client_credentials mail.agiloft.smtp.device-token-refresh.response.access_token.name=access_token mail.agiloft.smtp.device-token-refresh.response.expire.name=expires_in
- Locate each of these lines and replace the placeholders with your credentials. Make sure to replace only the placeholder text. Do not remove the equals sign (=) or any other text on the line.
mail.agiloft.smtp.tenant.id=TENANT_ID - Replace TENANT_ID with your Directory (tenant) ID.
mail.agiloft.smtp.client.id=CLIENT_ID - Replace CLIENT_ID with your Application (client) ID.
- mail.agiloft.smtp.device-auth-request.payload.3=client_secret=CLIENT_SECRET - replace CLIENT_SECRET with your client secret value.
- mail.agiloft.smtp.device-token.payload.3=client_secret=CLIENT_SECRET - replace CLIENT_SECRET with your client secret value.
- mail.agiloft.smtp.device-token-refresh.payload.3=client_secret=CLIENT_SECRET - replace CLIENT_SECRET with your client secret value.
- In Agiloft, go to Setup > System > Manage Global Variables and find the Custom SMTP Configuration Properties (mail_smtp_custom_options) variable.
- Edit the variable and paste the edited text from step 2 into the Global Variable Value field.
- Now, go to Setup > Email and SMS > Outbound Email Settings.
- SMTP server: GRAPH
- SMTP login: email address for the account being used to send emails
- Default outbound email address: the same email address as step 5b
- Select the Reset checkbox and click Finish.
- A confirmation message appears. If you see an error instead, read the message carefully to troubleshoot the problem.
- When you finish the authentication, return to Setup > Email and SMS > Configure Email Server and enter an email address to receive a test message, then click Finish.
- Confirm that a test message arrives at that address.
Client Code Flow for Inbound Email
Now, you're ready to configure inbound email.
- Go to Setup > Email and SMS > Inbound Email Accounts and click New or edit the existing account you want to change.
- On the Server tab, enter the following:
- Select IMAP and enter: GRAPH
- Select the SSL/TLS connection checkbox.
- Confirm that Custom Port is set to 993.
- Click Next. If a warning appears, you can safely ignore it.
- On the Account tab, enter the following:
- In the Email and Email Account fields, enter the email address that is registered to use the application.
- Leave the Password field empty.
- Under Activity, choose whether to have the account immediately poll for emails.
- Return to the Server tab. If you see a text box and a Reset button, proceed to the next step. If not, go to the Filters tab, click Finish, then edit the inbound configuration again and go to the Server tab.
Paste this code into a text editor:
#main setting and auth mail.inbound.auth.mechanisms=XOAUTH2 mail.agiloft.inbound.auth_flow=skip #Extended logging for troubleshooting mail.agiloft.inbound.trace=false mail.agiloft.inbound.tenant.id=TENANT_ID mail.agiloft.inbound.client.id=CLIENT_ID #DO NOT specify in case the refresh token long live time is undefined! #mail.agiloft.inbound.refresh-token.llt= # authorization request mail.agiloft.inbound.device-auth-request.url=https://login.microsoftonline.com/${mail.agiloft.inbound.tenant.id}/oauth2/v2.0/token mail.agiloft.inbound.device-auth-request.payload.1=client_id=${mail.agiloft.inbound.client.id} mail.agiloft.inbound.device-auth-request.payload.2=scope=https://graph.microsoft.com/.default mail.agiloft.inbound.device-auth-request.payload.3=client_secret=CLIENT_SECRET mail.agiloft.inbound.device-auth-request.payload.4=grant_type=client_credentials mail.agiloft.inbound.device-auth-request.response.user_code.name=code #device access token request mail.agiloft.inbound.device-token.url=https://login.microsoftonline.com/${mail.agiloft.inbound.tenant.id}/oauth2/v2.0/token mail.agiloft.inbound.device-token.payload.1=client_id=${mail.agiloft.inbound.client.id} mail.agiloft.inbound.device-token.payload.2=scope=https://graph.microsoft.com/.default mail.agiloft.inbound.device-token.payload.3=client_secret=CLIENT_SECRET mail.agiloft.inbound.device-token.payload.4=grant_type=client_credentials mail.agiloft.inbound.device-token.response.access_token.name=access_token mail.agiloft.inbound.device-token.response.expire.name=expires_in #new token and refresh token mail.agiloft.inbound.device-token-refresh.url=https://login.microsoftonline.com/${mail.agiloft.inbound.tenant.id}/oauth2/v2.0/token mail.agiloft.inbound.device-token-refresh.payload.1=client_id=${mail.agiloft.inbound.client.id} mail.agiloft.inbound.device-token-refresh.payload.2=scope=https://graph.microsoft.com/.default mail.agiloft.inbound.device-token-refresh.payload.3=client_secret=CLIENT_SECRET mail.agiloft.inbound.device-token-refresh.payload.4=grant_type=client_credentials mail.agiloft.inbound.device-token-refresh.response.access_token.name=access_token mail.agiloft.inbound.device-token-refresh.response.expire.name=expires_in
- Locate each instance of these placeholders, and replace them with your credentials:
- TENANT_ID - Replace this with your Directory (tenant) ID.
- CLIENT_ID - Replace this with your Application (client) ID.
- CLIENT_SECRET - Replace this with your client secret value in all three instances.
- Paste the modified text into the text box on the Server tab.
- Select the Refresh checkbox and click Next.
- Confirm that a message appears stating that communication was established, and sharing instructions to sign in. If you see an error message, retrace your steps and check your work.
- Click Next again and confirm that a message appears stating the account is valid. If you see an error message, retrace your steps and check your work.
- Complete the rest of the tabs according to Inbound Email Accounts.
Configure Device Code Flow
If you prefer to use device code flow instead of client code flow, follow these steps to set it up.
- In Entra, click API Permissions in the sidebar.
- Expand the Microsoft Graph row and edit the delegated permissions. Delegated permissions grant access to the app as the designated email account in Agiloft.
- Add all the OpenId permissions:
- openid
- offline_access
- profile
- Click Add a permission and choose Microsoft Graph in the pane that opens.
- In the Select permissions field, search and select Mail.Send and, if you're using a shared account, also Mail.Send.Shared.
- If you also plan to use Graph to handle inbound email, search and select Mail.ReadWrite and IMAP.AccessAsUser.All as well.
- If you're using a shared account, search and select Mail.ReadWrite.Shared as well.
- Click Authentication on the sidebar and select Allow Public Client Flow.
- At the top of the page, click Add Platform and enter
http://localhost
as the redirect URL.
Device Code Flow for Outbound Email
Now, you're ready to configure outbound email.
- Go to Setup > System > Manage Global Variables, click the Variables with Default Values tab, and edit the Custom SMTP Configuration Properties variable.
Paste this code into the text input box:
mail.smtp.auth.mechanisms=XOAUTH2 mail.agiloft.smtp.auth_flow=device mail.agiloft.smtp.tenant.id=TENANT_ID mail.agiloft.smtp.client.id=CLIENT_ID #DO NOT specify in case the refresh token long live time is undefined! #mail.agiloft.smtp.refresh-token.llt= #device authorization request mail.agiloft.smtp.device-auth-request.url=https://login.microsoftonline.com/${mail.agiloft.smtp.tenant.id}/oauth2/v2.0/devicecode mail.agiloft.smtp.device-auth-request.payload.1=client_id=${mail.agiloft.smtp.client.id} mail.agiloft.smtp.device-auth-request.payload.2=scope=user.read offline_access openid profile email https://outlook.office365.com/Mail.Send mail.agiloft.smtp.device-auth-request.response.code.name=device_code #mail.agiloft.smtp.device-auth-request.response.expires_in.name=expires_in mail.agiloft.smtp.device-auth-request.response.message.name=message #device access token request mail.agiloft.smtp.device-token.url=https://login.microsoftonline.com/${mail.agiloft.smtp.tenant.id}/oauth2/v2.0/token mail.agiloft.smtp.device-token.payload.1=grant_type=urn:ietf:params:oauth:grant-type:device_code mail.agiloft.smtp.device-token.payload.2=code=%CODE% mail.agiloft.smtp.device-token.payload.3=client_id=${mail.agiloft.smtp.client.id} mail.agiloft.smtp.device-token.response.access_token.name=access_token mail.agiloft.smtp.device-token.response.expire.name=expires_in mail.agiloft.smtp.device-token.response.refresh_token.name=refresh_token #new token and refresh token mail.agiloft.smtp.device-token-refresh.url=https://login.microsoftonline.com/${mail.agiloft.smtp.tenant.id}/oauth2/v2.0/token mail.agiloft.smtp.device-token-refresh.payload.1=client_id=${mail.agiloft.smtp.client.id} mail.agiloft.smtp.device-token-refresh.payload.2=scope=user.read offline_access openid profile email https://outlook.office365.com/Mail.Send mail.agiloft.smtp.device-token-refresh.payload.3=redirect_uri=http://localhost mail.agiloft.smtp.device-token-refresh.payload.4=grant_type=refresh_token mail.agiloft.smtp.device-token-refresh.payload.5=refresh_token=%REFRESH_TOKEN% mail.agiloft.smtp.device-token-refresh.response.access_token.name=access_token mail.agiloft.smtp.device-token-refresh.response.expire.name=expires_in mail.agiloft.smtp.device-token-refresh.response.refresh_token.name=refresh_token
- Locate these two lines near the top of the text and replace the placeholders with your credentials:
mail.agiloft.smtp.tenant.id=TENANT_ID - Replace TENANT_ID with your Directory (tenant) ID.
mail.agiloft.smtp.client.id=CLIENT_ID - Replace CLIENT_ID with your Application (client) ID.
- Save your changes and go to Setup > Email and SMS > Configure Email Server.
- Enter the following:
- SMTP server: GRAPH
- SMTP login: email address for the account being used to send emails
- Default outbound email address: the same email address as step 5b
- Select the Reset checkbox and click Finish.
- Note the message in red at the top of the screen. Follow the instructions there to complete authentication.
- When you finish the authentication, return to Setup > Email and SMS > Configure Email Server and enter an email address to receive a test message, then click Finish.
- Confirm that a test message arrives at that address.
Device Code Flow for Inbound Email
Now, you're ready to configure inbound mail.
- Go to Setup > Email and SMS > Inbound Email Accounts and and click New or edit the existing account you want to change.
- If creating a new configuration, select the table where the emails should be processed and click Next.
- Select IMAP (Microsoft Exchange) and enter the following: GRAPH:GRAPH
- Click Next and enter the inbound email address in the Email and Email Account fields.
- Clear the Password field.
- Go to the last tab and click Finish. Then, edit the same inbound configuration again and click Next.
Paste this code into the text input box:
mail.inbound.auth.mechanisms=XOAUTH2 mail.agiloft.inbound.auth_flow=device mail.agiloft.inbound.trace=false mail.agiloft.inbound.tenant.id=************ mail.agiloft.inbound.client.id=************ #DO NOT specify in case the refresh token long live time is undefined! #mail.agiloft.inbound.refresh-token.llt= #device authorization request mail.agiloft.inbound.device-auth-request.url=https://login.microsoftonline.com/${mail.agiloft.inbound.tenant.id}/oauth2/v2.0/devicecode mail.agiloft.inbound.device-auth-request.payload.1=client_id=${mail.agiloft.inbound.client.id} mail.agiloft.inbound.device-auth-request.payload.2=scope=user.read offline_access openid profile email https://outlook.office365.com/Mail.Read mail.agiloft.inbound.device-auth-request.response.code.name=device_code #mail.agiloft.inbound.device-auth-request.response.expires_in.name=expires_in mail.agiloft.inbound.device-auth-request.response.message.name=message #device access token request mail.agiloft.inbound.device-token.url=https://login.microsoftonline.com/${mail.agiloft.inbound.tenant.id}/oauth2/v2.0/token mail.agiloft.inbound.device-token.payload.1=grant_type=urn:ietf:params:oauth:grant-type:device_code mail.agiloft.inbound.device-token.payload.2=code=%CODE% mail.agiloft.inbound.device-token.payload.3=client_id=${mail.agiloft.inbound.client.id} mail.agiloft.inbound.device-token.response.access_token.name=access_token mail.agiloft.inbound.device-token.response.expire.name=expires_in mail.agiloft.inbound.device-token.response.refresh_token.name=refresh_token #new token and refresh token mail.agiloft.inbound.device-token-refresh.url=https://login.microsoftonline.com/${mail.agiloft.inbound.tenant.id}/oauth2/v2.0/token mail.agiloft.inbound.device-token-refresh.payload.1=client_id=${mail.agiloft.inbound.client.id} mail.agiloft.inbound.device-token-refresh.payload.2=scope=user.read offline_access openid profile email https://outlook.office.com/Mail.ReadWrite mail.agiloft.inbound.device-token-refresh.payload.3=redirect_uri=http://localhost mail.agiloft.inbound.device-token-refresh.payload.4=grant_type=refresh_token mail.agiloft.inbound.device-token-refresh.payload.5=refresh_token=%REFRESH_TOKEN% mail.agiloft.inbound.device-token-refresh.response.access_token.name=access_token mail.agiloft.inbound.device-token-refresh.response.expire.name=expires_in mail.agiloft.inbound.device-token-refresh.response.refresh_token.name=refresh_token
- Locate these two lines near the top of the text, and replace the asterisks with your credentials:
mail.agiloft.inbound.tenant.id=************ - Replace the asterisks with your Directory (tenant) ID.
mail.agiloft.smtp.client.id=************ - Replace the asterisks with your Application (client) ID.
- Click Next and note the message at the top of the screen. Follow the instructions there to complete authentication, using the email account that will be used for inbound mail.
- When you reach the confirmation screen, return to Agiloft and click Next.
- Confirm you see a message that confirms that communication was established.
- Complete the rest of the tabs according to Inbound Email Accounts. If you're using an existing configuration, you probably won't need to make any further changes.