﻿# Discarding expired messages


The MSMQ transport can discard messages that exceed a configured [Time-To-Be-Received (TTBR)](/nservicebus/messaging/discard-old-messages.md) in two ways: **natively** or through **non-native** handling by NServiceBus.

## Native

When a message with a TTBR value is sent, NServiceBus maps that value to the [native `TimeToBeReceived` property](https://learn.microsoft.com/en-us/dotnet/api/system.messaging.message.timetobereceived) of the MSMQ message. MSMQ continuously checks the TTBR of queued messages. Once a message has expired, it is automatically removed from the queue and the corresponding disk space is reclaimed.

> [!NOTE]
> MSMQ enforces a single Time-To-Be-Received value for all messages within a transaction. If multiple messages participate in the same transaction, the TTBR from the **first** message is applied to all. This can lead to unintended expiration and message loss.
>
> To prevent this, TTBR is **not supported by default** for endpoints using [transaction modes](/transports/transactions.md) `SendsAtomicWithReceive` or `TransactionScope`.

The MSMQ native TTBR implementation can be **disabled** for messages sent as part of a transaction. In this case, messages rely on [non-native TTBR handling](#non-native) to ensure they are discarded **at receive time** if the Time-To-Be-Received has expired. 

Messages sent **outside of a transaction** will still use MSMQ's built-in native TTBR functionality.

<!-- snippet: disable-native-ttbr -->

```cs
var transport = new MsmqTransport
{
    UseNonNativeTimeToBeReceivedInTransactions = true
};
endpointConfiguration.UseTransport(transport);
```

<!-- endsnippet -->

> [!WARNING]
> Messages sent **without** the native MSMQ `TimeToBeReceived` property cannot be automatically removed from the queue by MSMQ. They will remain in the queue until they are read by a receiving endpoint.
>
> If such a message is received by an endpoint running **NServiceBus.Transport.Msmq version 1.0.x or earlier**, the TTBR header will be ignored and the message may be processed even if it has already expired.

## Non-native

In addition to using MSMQ's native behavior, NServiceBus also includes a `NServiceBus.TimeToBeReceived` [header](/nservicebus/messaging/headers.md) on outgoing messages.

NServiceBus.Transport.Msmq version 1.0.x and earlier does **not** evaluate the `NServiceBus.TimeToBeReceived` header on incoming messages.

Starting with version 1.1, the transport will discard a message **without processing it** if **all** of the following conditions are met:

- The message contains an `NServiceBus.TimeSent` header.
- The message contains an `NServiceBus.TimeToBeReceived` header.
- The calculated cut-off time (Time Sent + Time To Be Received) has already passed.

> [!WARNING]
> The `NServiceBus.TimeSent` header reflects the **sender’s** system clock, while the cut-off time is evaluated using the **receiver’s** system clock. If the clocks are not properly synchronized, this can lead to messages being discarded prematurely.
>
> Avoid setting TTBR values in seconds or very short durations. If the allowed clock drift is up to 15 seconds and the TTBR is 30 seconds, the TTBR should instead be set to at least 45 seconds to prevent unintended expiration.
>
> Learn more about [clock synchronization issues](/nservicebus/messaging/discard-old-messages.md#clock-synchronization-considerations).

If necessary, the transport can be configured to **ignore** the `NServiceBus.TimeToBeReceived` header on incoming messages:

<!-- snippet: ignore-incoming-ttbr-headers -->

```cs
var transport = new MsmqTransport
{
    IgnoreIncomingTimeToBeReceivedHeaders = true
};
endpointConfiguration.UseTransport(transport);
```

<!-- endsnippet -->
