# Dead Letter Policy (/sdks/csharp/how-to/queues/dead-letter-policy)



<Callout type="info" title="Which to use">
  This page is the field-level reference for `MaxReceiveCount` and `MaxReceiveQueue`. For the end-to-end task — sending a message, exhausting retries, and consuming the diverted message — see [Dead Letter Queue](./dead-letter-queue).
</Callout>

## Overview [#overview]

`MaxReceiveCount` and `MaxReceiveQueue` are two properties on `QueueMessage` that together define the *dead-letter policy* for a single message. They are set once, at send time, and travel with the message — the retry ceiling is a producer decision, not something a consumer can override.

**Gotchas:** the receive count increments on *every* failed delivery — an explicit nack, an expired transaction, or a visibility timeout — not just deliberate rejections, so set the ceiling above your normal retry budget. The dead-letter channel is an ordinary queue with no special behavior: nothing drains it for you, so monitor it and build a reprocessing path or failures pile up silently.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* C# SDK installed (`dotnet add package KubeMQ.SDK.CSharp`)

## Code [#code]

```csharp title="Program.cs"
// KubeMQ .NET SDK — QueuesStream: Dead Letter Policy
//
// This example demonstrates configuring a dead letter queue (DLQ) with the downstream
// receiver API. After MaxReceiveCount failed attempts, the message moves to the DLQ
// channel. The receiver is used to poll and inspect DLQ messages.
//
// Prerequisites:
//   - KubeMQ server running on localhost:50000
//   - dotnet run

using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.Queues;
using System.Text;

await using var client = new KubeMQClient(new KubeMQClientOptions
{
    ClientId = "csharp-queues-dead-letter-policy-client",
});
await client.ConnectAsync();

Console.WriteLine("Connected to KubeMQ server");

// Send a message with DLQ configuration
await client.SendQueueMessageAsync(new QueueMessage
{
    Channel = "csharp-queues.dlp-source",
    Body = Encoding.UTF8.GetBytes("Order that will fail processing"),
    MaxReceiveCount = 3,
    MaxReceiveQueue = "csharp-queues.dlp-destination"
});

Console.WriteLine("Sent message with MaxReceiveCount=3 and DLQ configured");
Console.WriteLine("After 3 failed receive attempts, the message moves to 'csharp-queues.dlp-destination'");

await using var receiver = await client.CreateQueueDownstreamReceiverAsync();

// Check the DLQ via downstream receiver
var batch = await receiver.PollAsync(new QueuePollRequest
{
    Channel = "csharp-queues.dlp-destination",
    MaxMessages = 10,
    WaitTimeoutSeconds = 5,
});

if (batch.HasMessages)
{
    Console.WriteLine($"DLQ contains {batch.Messages.Count} message(s):");
    foreach (var msg in batch.Messages)
    {
        Console.WriteLine($"  {Encoding.UTF8.GetString(msg.Body.Span)}");
    }
    await batch.AckAllAsync();
}
else
{
    Console.WriteLine("No messages in DLQ yet (need to exhaust retries first)");
}

Console.WriteLine("Done.");

```

## Field reference [#field-reference]

* **`MaxReceiveCount`** (`int`) — the number of failed receives (unacknowledged, rejected, or expired-visibility) allowed before the broker reroutes the message. `MaxReceiveCount = 3` on a `QueueMessage` means the 3rd unacknowledged receive triggers the move.
* **`MaxReceiveQueue`** (`string`) — the channel name of the dead-letter destination. If empty, messages that exceed `MaxReceiveCount` are discarded rather than rerouted — always set it explicitly if you want failures preserved.
* Both properties are set on the `QueueMessage` at send time; there is no way to change the policy after the message has been queued.
* Pair `MaxReceiveQueue` with `ExpirationSeconds` if you also want messages to expire from the source queue before the receive limit is reached.

For the walkthrough of sending, exhausting retries, and consuming from the resulting DLQ, see [Dead Letter Queue](./dead-letter-queue).

## Related [#related]

* [Dead Letter Queue](./dead-letter-queue) — task-oriented walkthrough for DLQ routing
* [C# SDK Reference](/sdks/csharp/reference)
* [Send & Receive](/sdks/csharp/tutorials/send-receive)
* [Ack All](/sdks/csharp/how-to/queues/ack-all)
