Skip to content

Troubleshooting Graph Notifications (On-Premise)

This guide is for on-premise installations where new emails aren't imported right away for an Exchange Online account using Microsoft Graph API, and EmailEngine's log shows Failed to create MS Graph subscription.

When an account connects, EmailEngine asks Microsoft to send notifications to https://<public-host>/email/oauth/msg/.... Microsoft first sends a test request to that address and must get an answer within 10 seconds. If the request doesn't arrive in time, no notifications are set up. See Webhook Notifications for the setup.

All commands are for PowerShell. The logs are in these folders by default:

Log Location
EmailEngine %ProgramData%\Lundalogik\LIME Pro Server\EmailEngine\logs
nginx access log %ProgramData%\Lundalogik\LIME Pro Server\nginx\logs\access-YYYY-MM-DD.log

1. Read EmailEngine's Log

EmailEngine tries to set up notifications when an account connects, and logs the result in %ProgramData%\Lundalogik\LIME Pro Server\EmailEngine\logs. To find the latest attempts:

Get-ChildItem "$env:ProgramData\Lundalogik\LIME Pro Server\EmailEngine\logs\*.log" | Sort-Object LastWriteTime | Select-String -SimpleMatch "MS Graph subscription", "Service URL not set" | Select-Object -Last 20

If the latest attempt is from before the firewall or the setting was changed, go to step 4 first.

Look for one of these messages. They are separate problems with different fixes:

Message Cause and fix
Subscription validation request timed out Microsoft's test request didn't get an answer within 10 seconds. Continue with step 2 to find out why.
Service URL not set or service URL is not set Rare. EmailEngine's Service URL is empty. In Swagger, POST /v1/settings with {"serviceUrl": "http://127.0.0.1:3018"}, then see step 4.

If the command finds nothing, open the newest log file in the folder and read through it around the time of the latest attempt. Warnings have "level":40 and errors "level":50.

EmailEngine logs the time as a number in the time field, for example "time":1767225600000. To convert it to local time, replace <time> with that number:

[DateTimeOffset]::FromUnixTimeMilliseconds(<time>).LocalDateTime

2. Find Microsoft's Test Request in the nginx Log

This shows whether Microsoft's own request reached the server, and when. nginx writes one file per day in %ProgramData%\Lundalogik\LIME Pro Server\nginx\logs, named access-YYYY-MM-DD.log.

Select-String -Path "$env:ProgramData\Lundalogik\LIME Pro Server\nginx\logs\access-*.log" -Pattern "validationToken" | Select-Object -Last 20
  • No line at that time: the request never reached the server. Check that notificationBaseUrl is https://<public-host>/email, and that the firewall lets Microsoft in.
  • 404: the request reached the wrong place, usually because notificationBaseUrl is missing /email.
  • 502 or 504: nginx can't reach EmailEngine. Check that the lime-emailengine service is running.
  • 200: the server answered, but check when. Compare the time on the nginx line with the time of EmailEngine's error:

    • nginx line before the error: the request arrived in time, so the network isn't the problem. Double-check that you compare the right lines: the same account ID as in EmailEngine's error, the same time zone (the nginx line shows its offset, such as +0100), and both /msg/notification and /msg/lifecycle before the error. If they are right, read EmailEngine's log around that time for other errors.
    • nginx line after the error: the request reached the server after Microsoft had given up. Something in front of the server is delaying it. Continue with step 3.

    For example:

    EmailEngine:  09:14:10  Failed to create MS Graph subscription ... Subscription validation request timed out
    nginx:        [15/Jan/2026:09:14:52 +0100] "POST /email/oauth/msg/notification?account=...&validationToken=... HTTP/1.1" 200
    

    Microsoft sent its request at about 09:14:00 and gave up after 10 seconds, at 09:14:10. The request only reached the server at 09:14:52, 42 seconds too late.

If every line in the nginx log has the same internal IP address, a device in front of the server (a firewall, load balancer or proxy) forwards the traffic. That device is where to look for delays.

3. Test the Server, Then the Way In

On the server, straight to EmailEngine:

curl.exe -s -X POST -w "\nHTTP %{http_code} in %{time_total}s\n" "http://127.0.0.1:3018/oauth/msg/notification?account=test&validationToken=hello"

Then from a computer outside the customer's network:

curl.exe -s -X POST -w "\nHTTP %{http_code} in %{time_total}s\n" "https://<public-host>/email/oauth/msg/notification?account=test&validationToken=hello"

Both should print hello and HTTP 200 in well under a second. Keep account=test in the URL, without it EmailEngine answers 400 Invalid input. If the test on the server is fast but the one from outside is slow or fails, the delay is in the customer's network.

The test from outside can pass even when Microsoft's requests are blocked, for example by geo-blocking. Microsoft's own request in step 2 is what counts. If it arrived too late or not at all, the delay is in the customer's network too.

When the delay is in the customer's network, ask their IT department to check the firewall and any proxies in front of the server for geo rules, intrusion prevention (IPS) or similar on inbound traffic. Give them the time from EmailEngine's error so they can find the request in their logs. Microsoft lists the IP addresses it sends notifications from in Additional endpoints for Microsoft 365.

4. After the Fix

When the cause is fixed, check that new emails come in:

  1. Send a test email to the account and see if it shows up in Lime CRM within a minute. EmailEngine may already have recovered on its own.
  2. If not, restart the EmailEngine service, which reconnects all accounts, and send a new test email. Run PowerShell as administrator:

    Restart-Service lime-emailengine
    
  3. If it still doesn't work, remove the account in Lime Admin, add it again, and send a new test email.

  4. If it still doesn't work, go back to step 1 and read the logs again.