New guide: how to warm up a dedicated IP without hurting your reputation. Read now →
Log in
MigoSMTP
Webhooks and eventsUpdated 15 Oct 2026

Tracing a Single Email: Message Logs, Events and the Delivery Lifecycle

When one customer says an email never arrived, you need to follow that exact message from your application to the mailbox. This guide explains message IDs, queue IDs and SMTP transaction IDs, the event types you will see, how to correlate your own logs with platform events, how to tell a deferral from a bounce, and how to build a trace template and an internal event store.

AM
Written by Aarav Mehta
Head of Deliverability
Reviewed by Tomasz Kowalski
  • Published8 Sep 2026
  • Read time14 min
  • Length3,060 words
Share this guide

When a customer says an email never arrived, the fastest way to an answer is to read the email message logs for that one message and follow it from your application to the receiving mail server. Guessing at DNS records or sending rates before you have seen the timeline wastes hours. This guide shows us how to identify a message across systems, read the events in the right order, tell a temporary deferral from a permanent bounce, write a trace that support can act on, and build a small internal event store so that the next investigation takes minutes instead of days.

3identifiers to keep apart: message, queue and transaction
9common event types covered below
2failure classes: temporary and permanent
1trace template to paste into every ticket

The three identifiers: message ID, queue ID and SMTP transaction ID

Most confusion in a trace comes from treating three different identifiers as one. They live at different layers, they are created by different systems, and they answer different questions. If you collect the right one at send time, a later search is simple. If you did not, you will be searching by recipient and time, which is slower and less certain.

IdentifierCreated byScopeBest use
Message IDYour platform when it accepts the message, or the Message-ID header the sender or server writesThe message across its whole lifePrimary search key across platform logs, webhooks and your own records
Queue IDOne mail server for its own queueThat server only, and only while the message is queued thereMatching lines in a single server log, or quoting a remote server answer
SMTP transaction IDThe sending or receiving server for one connection and one delivery attemptOne attempt, which may carry one or more recipientsShowing exactly which attempt got which response
Your correlation IDYour application, before it calls the platformYour own business action, such as one order confirmationLinking your logs, your database row and the platform events

The message ID is the one to build around. The Message-ID header is defined in RFC 5322 and is meant to be unique for each message. Many receiving servers also write their own queue or transaction ID into the text of their reply, for example the words queued as followed by a short string. That string is valuable because the recipient administrator can search for it, so keep the full reply text in the trace. Our guide on reading email headers shows where each of these appears in a delivered message.

Keep it simple. Generate your own correlation ID for every send, pass it to the platform in whatever custom metadata or header field your MigoSMTP account supports, and store the message ID the platform returns next to it. Then either ID finds the other.

The lifecycle of one email, step by step

A message passes through a series of states. The SMTP conversation itself is defined in RFC 5321, and the status codes that come back are structured by RFC 3463 and the delivery reports by RFC 3464. Platforms turn those steps into named events. The names below are generic, so check your MigoSMTP account for the exact event names, fields and retention.

  1. Your application builds the message and writes a log line with your correlation ID, recipient and template.
  2. The platform accepts it over SMTP or the API. From this point the platform owns the message and returns a message ID.
  3. The message is queued and waits for a delivery slot, shaped by rate limits and the recipient domain.
  4. A delivery attempt is made. The platform connects to the receiving server and walks through the SMTP commands.
  5. The receiver answers. A 2xx reply means accepted, a 4xx reply means try later, and a 5xx reply means refused.
  6. The message ends as delivered, or as bounced after a permanent refusal or after the retry window closes.
  7. Recipient signals follow later, such as an open, a click, a complaint or an unsubscribe.

Event types and what each one tells you

Event names differ between platforms, but the meanings are stable. Use the table to translate whatever you see into one of these stages, and to know how much weight to put on it.

EventMeaningFinal or interimHow much to trust it
AcceptedThe platform took responsibility for the message after validating the requestInterimHigh. It proves hand-off to the platform, nothing more
QueuedThe message is waiting for a delivery attemptInterimHigh. A long stay here points to rate limits or a paused stream
DeferredThe receiver or the network asked us to try later, with a 4xx reply or a timeoutInterimHigh. Read the reply text, because it names the reason
DeliveredThe receiving server accepted the message with a 2xx replyFinal for deliveryHigh for hand-off, none for folder placement
BouncedA permanent refusal, or the retry window endedFinal failureHigh. Look at the enhanced status code
ComplainedThe recipient marked the message as spam and the mailbox provider reported itSignal after deliveryMedium. Not every provider reports complaints
OpenedA tracking image was requestedSignal after deliveryLow to medium. Privacy features distort it
ClickedA tracked link was followedSignal after deliveryMedium. Security scanners can click links too
UnsubscribedThe recipient used an unsubscribe link or headerSignal after deliveryHigh. Must update your suppression data

Notice that only two of these events end the delivery story, and the rest are interim or happen afterwards. A ticket that says the email was accepted is not saying it was delivered, and a ticket that says delivered is not saying it was read. Keeping those claims separate prevents a lot of back and forth. For what to do with bounces, complaints and unsubscribes after the trace, see suppression list management.

Correlating your application logs with platform events

A trace only works if the two sides share a key. The simplest design has three parts: write the correlation ID before sending, capture the message ID in the send response, and log both on one line. After that, every webhook event carries the message ID, so a join on that field links your business action to the whole timeline.

What to log in your application

  • Correlation ID. A random unique value, such as a UUID, created once per business action and reused on retries of the same action.
  • Message ID returned by the platform. Store it in the same log line and in the database row for the order, user or ticket.
  • Recipient and template name. Enough to search, without logging the message body.
  • Time with a time zone. Use UTC everywhere, and write the offset explicitly.
  • The API or SMTP response. A success response means accepted by the platform, so log it under that name and not under delivered.

Here is an invented example of the two sides of one send. The application log line and the platform events share the message ID. All names, addresses and values are made up for illustration.

app.log
2026-03-12T09:14:02Z INFO mail.send corr=ord-88213-confirm to=jo@example.org template=order_confirmation
2026-03-12T09:14:03Z INFO mail.accepted corr=ord-88213-confirm msg_id=m-5f2a91c0 status=accepted

platform events (JSON, one per line)
{"event":"accepted","msg_id":"m-5f2a91c0","rcpt":"jo@example.org","ts":"2026-03-12T09:14:03Z"}
{"event":"queued","msg_id":"m-5f2a91c0","rcpt":"jo@example.org","ts":"2026-03-12T09:14:03Z"}
{"event":"deferred","msg_id":"m-5f2a91c0","rcpt":"jo@example.org","attempt":1,"code":"451","enhanced":"4.7.1","reply":"Greylisted, try again later","ts":"2026-03-12T09:14:05Z"}
{"event":"delivered","msg_id":"m-5f2a91c0","rcpt":"jo@example.org","attempt":2,"code":"250","reply":"2.0.0 OK queued as 7Hq91","ts":"2026-03-12T09:19:06Z"}
{"event":"opened","msg_id":"m-5f2a91c0","rcpt":"jo@example.org","ts":"2026-03-12T09:41:50Z"}

Read the example from the top. The application handed over the message at 09:14:02 and got an acceptance a second later. The first delivery attempt was deferred with a 451 reply, which means try later. The second attempt, five minutes afterwards, got a 250 reply and the message was delivered. The customer then opened it. If the customer complained at 09:15 that nothing had arrived, the trace shows a normal retry and nothing to fix.

Matching on events your platform sends you

Platform events usually reach you through webhooks. Our guide to email webhooks and signature verification explains how to receive them safely, and reliable webhook handling explains duplicates and ordering. For tracing, the important rules are to verify each request, store the raw event before you transform it, and index on the message ID and the recipient.

Reading a deferral versus a bounce

The most useful skill in a trace is separating a message that is still in progress from one that has failed. The first digit of the SMTP reply code decides this. A 4xx reply is a temporary failure, and a 5xx reply is a permanent failure. RFC 3463 adds an enhanced status code of three numbers, such as 4.7.1 or 5.1.1, where the first number repeats the class, the second names the subject, and the third gives the detail.

SignalDeferralBounce
SMTP class4xx, or a connection timeout5xx
Enhanced code starts with4.5.
What the receiver is sayingNot now. Try again laterNo. Do not try again
What we do nextRetry on a schedule with growing gapsStop, record the failure and update suppression data
Typical causesGreylisting, rate limiting, mailbox busy, temporary DNS or network trouble, reputation throttlingUnknown user, invalid domain, policy block, authentication failure, message too large
What you doWait, watch the trend, slow down if the reply asks for itRead the code, fix the address or the cause, and do not resend blindly

A deferral can turn into a bounce when the retry window ends, and in that case the final reason is often the last deferral reply, so read the whole history. A single deferral is normal. Many deferrals for one receiving domain at the same time point to throttling, and our guide to rate limits, retries and backoff explains how to respond. For a catalogue of codes and fixes, see SMTP bounce codes explained.

Quote the reply, do not paraphrase it. The text after the status code often names the exact rule or the exact policy that applied. Paste it into the ticket word for word, including any URL or reference string the receiver included.

A worked example: the missing invoice email

A customer writes at 15:00 that the invoice email for invoice 4471 did not arrive. Support has the customer address and an approximate send time of 14:30. They follow the steps in this guide with invented numbers, shown here to illustrate the method.

  1. Support searches the application log for the recipient and finds correlation ID inv-4471-send with message ID m-c3d870aa, logged at 14:31:10 UTC.
  2. They search the platform events for that message ID and find five events: accepted at 14:31:11, queued at 14:31:11, deferred at 14:31:14, deferred at 14:46:15, and bounced at 15:02:40.
  3. Both deferrals carry code 452 with enhanced code 4.2.2 and the reply text mailbox full. The bounce carries code 552 with enhanced code 5.2.2 and the reply text over quota.
  4. They classify the case. The message was accepted by us and attempted three times. Two attempts were temporary refusals and the third was a permanent one, all pointing to the recipient mailbox being over quota.
  5. They conclude that this is not a sending problem and not an authentication problem. The cause sits at the recipient end.
  6. They reply to the customer with the facts and the time of each attempt, ask for an alternative address, and send the invoice there. They also check that the original address is now in the suppression data so that the next invoice is not attempted until it is updated.

The whole investigation took four searches and a few minutes, because the identifiers were stored at send time. Without the message ID support would have searched by recipient and time, found the same events, and still needed to be sure it was the right message when the customer had received several that day.

A support-ticket-ready trace template

Whether the ticket goes to your own operations team or to us, the same template saves time. Fill every line you can, and write unknown where you do not have the value. Do not paste message bodies or full headers that contain private content unless asked, and remove anything the reader does not need.

TRACE REPORT
Summary: One sentence on what the sender or recipient expected and what happened.
Account / stream: sending account name and stream, for example transactional
Message ID: m-5f2a91c0
Correlation ID: ord-88213-confirm
Recipient (or domain only, if sensitive): jo@example.org
Sent (UTC): 2026-03-12T09:14:02Z
Template / message type: order_confirmation
Timeline (UTC, in order):
  09:14:03 accepted
  09:14:03 queued
  09:14:05 deferred  451 4.7.1  Greylisted, try again later
  09:19:06 delivered 250 2.0.0  OK queued as 7Hq91
Final state: delivered
Exact reply text from receiver: 250 2.0.0 OK queued as 7Hq91
What has already been checked: address spelled correctly, not in suppression data, SPF/DKIM/DMARC pass
Impact: one customer, one message, no pattern seen
Question / request: Please confirm the retry schedule that applied.

Retention and privacy of logs

Logs are useful because they are detailed, and that same detail makes them sensitive. A message log can include an email address, an IP address, a user agent string, a location inferred from an IP, a subject line and the time a person read a message. In many places that is personal data, and the rules about collecting, keeping and deleting it apply to you as the controller. Our guide on GDPR and email records covers the consent side of this.

Platform retention

Every sending platform keeps event and message data for a limited time. Check your MigoSMTP account for the exact retention period, which fields are stored, and whether you can export data before it expires. Do not assume a long window. If a policy question needs you to answer something from six months ago, plan to keep your own record instead of relying on the platform.

Your own retention rules

  • Keep what you need. A minimal record, with message ID, recipient hash or address, event type, code and timestamp, answers most questions.
  • Do not store bodies. Message content can include invoices, codes and personal details that make a log a risk. Store the template name and a version instead.
  • Set a deletion schedule. For example, keep detailed events for a short window and a reduced record for longer, and write down your reasons.
  • Restrict access. Support may need to search events, but few people need raw exports.
  • Handle erasure. When you delete a person, delete or anonymize their events in your event store too, and keep a suppression entry that does not expose the address if you can.
  • Protect secrets. Never log passwords, API keys, one-time codes or full password reset links. See our guide to API key security for the wider rules.

Building a searchable internal event store

Relying on a dashboard works until you need to answer a question the dashboard was not built for. A small internal event store, fed by webhooks, gives you your own history, your own retention and your own search. You do not need a large system to start. A single database table with the right indexes handles a lot of traffic.

FieldPurposeIndex it?
event_idUnique ID from the platform if present, used to drop duplicatesYes, unique
msg_idThe message ID, the primary join keyYes
corr_idYour correlation ID, copied from your send log or metadataYes
rcpt_hashA hash or the address of the recipient, depending on your privacy rulesYes
event_typeNormalized type such as accepted, deferred, delivered, bouncedYes, with time
event_tsTime reported by the platform, in UTCYes
received_tsWhen your handler received the requestNo
smtp_code and enhancedThe reply code and the enhanced status codeOptional
reply_textThe receiver text, truncated to a safe lengthNo
rawThe original payload, for replay and audit, kept for a shorter timeNo

Design rules that save you later

  1. Verify, then store raw. Check the signature, write the untouched payload, and only then parse it. If your parser has a bug, you can replay.
  2. Be idempotent. The same event can arrive twice. Use a unique key so that the second insert does nothing.
  3. Sort by event time. Use the platform timestamp for the timeline and your receive time only for debugging your handler.
  4. Normalize event names. Map the platform names into your own small set, so that a future change of platform does not break reports.
  5. Derive a current state. Keep a second table or view with one row per message and recipient holding the latest state, so support sees the answer at once.
  6. Reconcile. Compare your store with the platform data on a schedule, and fill gaps if a webhook failed.

Once the store exists, it also feeds the numbers you care about. Deferral rates by domain, time to deliver and bounce reasons are all queries over the same table, and our guide to deliverability metrics explains which of them matter.

Common tracing mistakes

  • Treating accepted as delivered. Acceptance by the platform is the beginning of the story.
  • Searching only by recipient. It works until the same person receives several messages in the same hour.
  • Mixing time zones. A two-hour offset can make a normal retry look like a failure.
  • Ignoring per-recipient events. One message to several people is several outcomes.
  • Trusting opens. A missing open is not a missing email.
  • Dropping the reply text. The code says what class of problem happened, and the text says why.
  • Resending before reading. A repeated send to a permanently failing address hurts your reputation and teaches you nothing.

A short checklist

  1. Every send creates a correlation ID and stores the platform message ID next to it.
  2. Application logs say accepted for a platform success and never say delivered.
  3. Webhook events are verified, stored raw, deduplicated and indexed by message ID and recipient.
  4. Timelines are sorted by event time in UTC.
  5. Deferrals and bounces are separated by the status code class and read with the full reply text.
  6. Tickets use the trace template, with exact reply text and what has been checked.
  7. Retention, access and erasure rules for logs are written down and match your privacy policy.
  8. Message bodies, secrets and one-time codes are never written to logs.

Stuck on a trace? Send us the filled-in template with the message ID and the timeline, and we will help you read it. Check your MigoSMTP account for the exact event names and retention that apply to you.

Contact support

Further reading and sources

Frequently asked questions

What is the difference between a message ID and a queue ID?

A message ID identifies the message itself, usually the Message-ID header or an ID that your sending platform returns when it accepts the message. A queue ID is an internal handle that one mail server uses while the message sits in its queue, and it normally means something only on that server. Use the message ID to search across systems and the queue ID only when someone looks at one server log.

Why does one email show several events?

Each step in the lifecycle produces its own event. A message may be accepted, queued, deferred once or twice, delivered, and later opened or clicked. A message with several recipients can also produce a separate set of events per recipient, so count events per recipient and not per message.

How long should a deferred message keep retrying?

That depends on the sending platform settings and on the receiving server behaviour, so check your MigoSMTP account for the exact retry schedule. In general a message is retried over a period of hours to days with growing gaps between attempts, and it becomes a bounce when the retry window ends. See our guide on rate limits, retries and backoff for how to design around this.

Is a delivered event proof that the email reached the inbox?

No. Delivered normally means the receiving server accepted the message with a 2xx response. After that the receiver may still place it in a spam folder, quarantine it or filter it by rule. Delivered tells you the hand-off worked, and it does not tell you the folder.

Can I rely on open events to confirm a message was read?

Not fully. Open tracking usually depends on a tiny image loading, which privacy features, image blocking and mailbox proxies can distort. Treat opens as a rough signal and treat delivered, bounced, complained and unsubscribed events as the reliable ones.

What should I put in a support ticket about a missing email?

Include the message ID, your own correlation ID, the recipient domain, the send time with a time zone, the event timeline and the exact response text from the receiving server. Add what you have already checked. A ticket with those items can usually be answered without a round trip of questions.

How long should I keep message logs?

Keep them as long as you need to answer disputes and investigations, and no longer than your privacy policy and local law allow. Platform retention differs by account, so check your MigoSMTP account for the exact period. Many teams keep a short-lived full record and a longer-lived minimal record without message content.

Do logs contain personal data?

Yes, usually. Recipient addresses, IP addresses, user agents and sometimes subject lines are personal data in many jurisdictions. Limit who can read them, avoid storing message bodies, delete on a schedule, and handle erasure requests across your event store as well as the platform.

Why do my webhook events arrive out of order?

Events are produced by different parts of the system and delivered over the network with retries, so a later event can arrive before an earlier one. Sort by the event timestamp and not by arrival time, and make your handler safe against duplicates. Our guide on reliable webhook handling covers this in detail.

Topics#message logs#message id#queue id#smtp transaction#delivery events#deferred#bounced#delivered#webhooks#event store#log retention#support ticket
Was this guide helpful?Your answer helps us improve our documentation.

Start sending in minutes.

Create an account, add your domain and send your first email.

Start free Talk to sales