Azure Comms Service returning RestError due to time difference when email volume is high

Matt Worsley 20 Reputation points
2025-03-12T17:37:29.1533333+00:00

I'm using the @azure/communication-email EmailClient SDK in my Node server (hosted as an App Service). The client listens for 'email-ready' events my Service Bus (via business logic in my app) and sends the email using emailClient.beginSend().

It works fine apart from when volumes are higher, say 100 sends per minute. In those cases it returns, intermittently, the error :

RestError: The given request could not be resolved. The time difference between the originating client and the server is greater than the allowed margin of 5 minutes. at handleErrorResponse (C:\home\site\wwwroot\node_modules\@azure\core-client\dist\commonjs\deserializationPolicy.js:148:19) at deserializeResponseBody (C:\home\site\wwwroot\node_modules\@azure\core-client\dist\commonjs\deserializationPolicy.js:83:45) at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

I can't find any guidance on this error in the docs. All I can do at the moment is implement retry logic, but if the volume is consitantly high, it just keeps raising the same error over and over.

I have checked on Kudu and the server time on my App Service is correct and hasn't drifted during these peak periods

Azure Communication Services
Azure Communication Services
An Azure communication platform for deploying applications across devices and platforms.
1,239 questions
{count} votes

Accepted answer
  1. Suresh Chikkam 2,135 Reputation points Microsoft External Staff Moderator
    2025-04-03T09:19:43.0933333+00:00

    Hi Matt Worsley,

    ACS uses shared access keys under the hood to sign each request with a timestamp, and the backend checks that the time difference is within a 5-minute window. If your EmailClient instance is long-lived, or if there’s a delay between token creation and request execution (like retries or queue delays), that timestamp can go stale — and ACS rejects it.

    • Rather than reusing a single client instance across all sends, I now just create a new one per email (or per small batch). That ensures the timestamp used for signing is always fresh and reduces the chance of drift.
    const emailClient = new EmailClient(process.env.EMAIL_CONNECTION_STRING);
    const poller = await emailClient.beginSend(message);
    await poller.pollUntilDone();
    
    • If you’re in a position to use Azure AD (via DefaultAzureCredential or ClientSecretCredential), do it. These tokens are refreshed automatically and are much more resilient under load. You’ll avoid the time skew problem entirely.
    const credential = new DefaultAzureCredential();
    const emailClient = new EmailClient(endpoint, credential);
    

    Unfortunately, ACS doesn’t support batch email sends yet — each beginSend() call is for one email. So you’ve got to optimize around single sends.

    Hope it helps!


    Please do not forget to click "Accept the answer” and Yes wherever the information provided helps you, this can be beneficial to other community members.

    User's image

    If you have any other questions or still running into more issues, let me know in the "comments" and I would be happy to help you.

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.