LEARN · DEBUGGING GUIDE

Email queued but not delivered: diagnose acceptance, backlog and safe recovery

Queued, accepted and delivered describe different checkpoints. Identify which system owns the message now before resending it, draining a backlog or extending a job’s lifetime.

Microsoft 365 outage: triage and practice hub

Editorial note

Independent evergreen debugging guidance, reviewed against the linked official documentation on 13 November 2026. These failure patterns do not establish the cause of any live Microsoft 365 incident. Buglyst is not affiliated with Microsoft.

IntermediateMicrosoft 365 reliability4 min read

What this usually means

There are several independent failure planes: the user’s client, your application queue, the mail submission API, Exchange transport and the recipient’s filtering or mailbox. A Graph sendMail response of 202 Accepted confirms request acceptance, not completed processing or delivery. A growing application queue does not, by itself, prove that Exchange has the same backlog or that a particular live incident caused it.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Choose one representative message and build a timestamped chain from application job creation to the last confirmed checkpoint.
  • 2Check whether the item is still in a client Outbox, waiting in your queue, accepted by Graph, or visible in Exchange message trace.
  • 3Record the original application operation identity and submission outcome without copying message bodies or recipient lists into incident chat.
  • 4Separate a definite rejection from a timeout with an unknown result before deciding whether replay is appropriate.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • searchOutlook’s Outbox and connection state for client-side submission questions.
  • searchApplication job age, original expiry, next-attempt time, attempt count and acknowledgement or lease history.
  • searchGraph response status and redacted correlation identifiers, followed by authorised Exchange message trace.
  • searchNon-delivery reports, quarantine or filtering results, interpreted with the organisation’s mail administrator.
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningA client has not submitted the message, despite a locally composed or queued state.
  • warningA dependency delays transport after accepting a submission; request success was incorrectly labelled delivered.
  • warningAn application resets expiry on each retry, keeping obsolete mail alive indefinitely.
  • warningA timeout or expired worker lease leads to replay of an operation whose earlier outcome was already successful.
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildUse distinct application states for queued, submission accepted, uncertain, rejected and expired; only claim delivery when supported by relevant evidence.
  • buildPreserve the original business deadline across retries. Expired jobs should stop, even when the dependency later recovers.
  • buildPause or limit admission during recovery, then resume a small measured batch while monitoring dependency responses and queue age.
  • buildReconcile uncertain and already accepted operations before replay; apply endpoint-specific guarantees rather than assuming mail sends deduplicate automatically.
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedTest a controlled internal message end to end and distinguish API acceptance time from the downstream result visible to administrators.
  • verifiedUse a fake clock to prove retries cannot move a queued job’s original expiry later.
  • verifiedSimulate a response lost after acceptance and a worker lease expiring during submission; verify the uncertain state is retained for reconciliation.
  • verifiedCheck that a recovery batch reduces eligible backlog without reviving expired jobs or producing duplicate logical sends.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningDo not click Send repeatedly, bulk replay every queued job, or label all missing mail as a single provider failure.
  • warningDo not promise a universal delivery time or assume a delivery-status label proves the recipient read the message.
  • warningDo not rotate identities, weaken authentication or bypass security policy to force an overloaded mail path.
( 08 )Follow the last confirmed checkpoint

A browser confirmation, a worker acknowledgement and an Exchange trace answer different questions. Write down exactly what each confirms. A job acknowledged before an actual submission can disappear from your queue without ever reaching Graph. Conversely, an accepted submission can leave your application queue correctly while downstream transport still takes time. Neither observation alone establishes final recipient delivery.

Message trace helps an authorised administrator investigate what Exchange received and how it handled a message. Search using a narrow time range and appropriate identifiers. Its results can be delayed, so a missing entry is not immediate proof that submission never happened. Investigate quarantine, filtering or external recipient handling separately when the transport evidence points there.

( 09 )Do not let retries make a time-sensitive message immortal

Consider a reminder created at 09:00 with a 09:15 deadline. If its 09:14 retry changes expiry to fifteen minutes from now, it has silently become eligible until 09:29. Repeating that calculation turns a brief outage into a stream of obsolete notifications. Store the original deadline once; a later attempt may change its next scheduled time, not the business expiry.

Before an attempt, compare the current time, original expiry and any server-directed wait. If the wait would cross expiry, stop or move the job to the explicitly designed review path. Do not send expired verification links or meeting reminders simply to make a queue-depth graph look healthy. The correct terminal state can be expired rather than sent.

( 10 )Treat recovery as a controlled release of work

Classify the backlog before draining it: unsent eligible jobs, expired jobs, confirmed accepted submissions and unknown outcomes. Start with a small concurrency limit and watch oldest eligible job age, success rate, throttling, unknown outcomes and duplicates. A lower queue count is useful only if the work completed correctly. Reduce pressure again when the dependency signals it needs space.

The Graph retry guide explains Retry-After; the Outlook guide covers client-versus-service scope. Buglyst’s free account lab simulates the queue-expiry bug without sending email. For a no-signup introduction to request boundaries, choose the pagination starter from the outage debugging hub.

Frequently asked questions

Does Graph sendMail returning 202 mean the email arrived?

No. The documented response means the request was accepted; processing is not necessarily complete. Use the relevant downstream evidence, such as authorised Exchange message trace, to investigate mail handling.

Can I resend every message when Microsoft 365 looks healthy again?

First separate unsent, expired, accepted and uncertain operations. Replaying an accepted or ambiguous send can create another email. Resume eligible work in controlled batches and reconcile uncertain results.