# Resubmitting messages

Sending a recorded message again, and what changes when you do.

The audit log stores the message body itself, not only the metadata about it. That means a message that failed can be sent again from the screen where you found it, without going back to whoever sent it in the first place and asking them to repeat it.

## What can be resubmitted {#what-can-be-resubmitted}

Not everything. A resubmittable event is one where sending the payload again is a meaningful action:

| Source | Event | What resubmitting does |
| --- | --- | --- |
| REST outgoing | Request sent | Sends the same request through the same connection again |
| SMTP | Request sent | Sends the same mail again |
| FHIR outgoing | Request sent | Sends the same FHIR request again |
| MLLP outgoing | Message sent | Sends the same HL7 message again and records the ACK that comes back |
| MLLP outgoing | Request sent | Sends the same request to that one destination again |
| MLLP channels | Message received | Re-runs the received message through the channel's service |
| File transfer | Delivered, delivery failed | Runs the stored file through the schedule's service again |

Anything else - a response, a pub/sub delivery, a scheduler run, a config change - has no resubmit action, because there is nothing sensible to repeat.

Two further things stop an otherwise resubmittable event from being sent again: the event no longer exists because retention deleted it, or it has no payload because it was only ever a reconciliation record. An empty payload is not the same as no payload - a GET with no body resubmits perfectly well.

## Resending against reprocessing {#resending-against-reprocessing}

Both actions read `Resubmit` on screen. Which one happens depends on the direction of the message.

**Resending** applies to a message you sent. The stored payload is sent again through the same outgoing connection, to the same remote system. Use it when the failure was on the far side or in between - a timeout, a 503, a connection refused.

**Reprocessing** applies to a message you received. The stored payload is fed back into the machinery that handles incoming messages, so your own service runs again on it. Use it when the failure was on your side - a service that raised an exception, a downstream system that was down when the message first arrived.

The classification column on the [listing](https://zato.io/docs/admin/audit-log/views.html) helps with the choice. A failed event is classified as **transient** when its error looks like a timeout, a refused connection or an unavailable system - resubmitting the message as-is can work. It is classified as **permanent** when the error points at the message itself - validation, a malformed payload, an unknown identifier - so the payload needs to change before another attempt. A failure matching neither pattern stays unclassified.

## Editing the payload first {#editing-the-payload-first}

The stored payload does not have to be resent exactly as it was recorded. Both resends and reprocesses accept an edited payload in its place - for the message that failed *because* of its content, a malformed segment or a wrong identifier, fix the payload and resubmit the fixed version. The new attempt lands as its own audit event, linked to the original by the correlation ID, so the record shows both what arrived and what was actually sent again.

A reprocess can also be narrowed to named destinations - the message reaches those alone, so a receiver that missed it can be caught up without every other destination being sent it twice.

## Resending one hop {#resending-one-hop}

Some messages fan out. One incoming HL7 message can be delivered to several destinations, and one of them can fail while the others succeed.

A hop resend deals with exactly that. It sends the stored payload to that one destination again, without re-running the service that produced it and without touching any other destination. Nobody who already has the message gets it twice.

## Resubmit a message {#resubmit-a-message}

1. Find the event on the [audit log listing](https://zato.io/docs/admin/audit-log/views.html).
2. Click `Resubmit` in the row's `Actions` column.
3. A confirmation appears, naming the connection and the message so you can see what is about to be sent before it goes.
4. Click `Yes, resubmit`.

![The resubmit confirmation](https://zatosource-production.b-cdn.net/docs/gfx/audit-log/resubmit.webp?v=1789221710)

Dashboard menu: Monitoring > Audit log

The result appears in place - either `Resubmitted` with the new correlation ID, or the failure and its error. A message that has already been resubmitted says so instead of offering the action again, so the same message is never delivered twice by accident.

## Learn more {#learn-more}

- [Production checklist](https://zato.io/docs/admin/production-checklist.html) - What to confirm before an environment takes real traffic
- [Audit log](https://zato.io/docs/admin/audit-log/) - Every request, response and error, and what you can do with them afterwards
- [Health checks](https://zato.io/docs/admin/health-checks.html) - Have Zato ping your outgoing connections instead of waiting for traffic to fail
- [Logging](https://zato.io/docs/admin/logging.html) - What is written where, and how to ship it to Splunk, Loki, Elastic or Datadog
- [GitOps with enmasse](https://zato.io/docs/admin/enmasse.html) - Keep the whole environment in git as YAML and import it anywhere
