---
title: "client.Signatures"
description: "Every method in this namespace: its signature, its parameters, what it returns and an example."
url: "https://openemail.uk/docs/csharp/reference/signatures"
area: "C#"
category: "Reference"
---

# client.Signatures

Every method in this namespace: its signature, its parameters, what it returns and an example.

## Methods

The signatures each address keeps: list them, add one, rename or rewrite it, choose which one signs new mail and which one signs replies and forwards, copy one to other addresses, and delete it.

### `Signatures.ListAsync`

List the signatures of the workspace or of one address, a page at a time

```csharp
Task<Page> ListAsync(
    string? address = null,
    int? limit = null,
    string? cursor = null,
    string? apiKey = null,
    CancellationToken cancellationToken = default)
```

Returns one page of signatures, sorted by address and then oldest first. `Signatures.ListAllAsync` collects every page and `Signatures.IterateAsync` walks them lazily. An address keeps a list of named signatures, as its Signature tab in the app shows. At most one of them is the default for new mail (`isDefault`) and at most one the default for replies and forwards (`isReplyDefault`), and one signature can be both.

Give `address:` to read the signatures of one address, or of a catch-all with `*@example.com`. Without it the list holds every address. An address that only ever had the single signature of earlier versions shows it here as one signature called `Signature`, default for both.

`Emails.SendAsync` adds the default of the address it sends from, and takes `signatureId` to add any other signature of that address instead.

Scopes: `settings:read`.

**Parameters**

- `address` (`string?`): One address, such as `hello@example.com`, or `*@example.com` for the catch-all of a domain. Left out, every address is listed.
- `limit` (`int?`): Page size, from 1 to 100. The server defaults to 25.
- `cursor` (`string?`): The `nextCursor` of the previous page, passed back as it came. Leave it out for the first page.
- `apiKey` (`string?`): Overrides the client's API key for this call only.
- `cancellationToken` (`CancellationToken`): Cancels the request.

**Returns**

A `Page` of signature objects, with `items`, `hasMore` and `nextCursor`. Each item has `id`, `address`, `name`, `html`, `isDefault`, `isReplyDefault`, `createdAt` and `updatedAt`.

**Example**

```csharp
var page = await client.Signatures.ListAsync(address: "hello@example.com");

foreach (var signature in page)
{
    Console.WriteLine($"{signature["name"]}{((bool?)signature["isDefault"] == true ? ", signs new mail" : string.Empty)}{((bool?)signature["isReplyDefault"] == true ? ", signs replies" : string.Empty)}");
}

if (page.HasMore)
{
    var next = await client.Signatures.ListAsync(address: "hello@example.com", cursor: page.NextCursor);

    Console.WriteLine($"{next.Count} more");
}
```

**Notes**

- A key or an app limited to particular addresses or domains sees only the signatures of the addresses it holds, and those of a catch-all only when it holds the domain whole.
- An `address:` that is not an address, or that names a whole domain with `@example.com`, is a 422 `invalid_parameter`.
- The cursor is opaque and holds where the last row sat in this order, so a signature added or deleted between pages never breaks the walk. A cursor this list did not hand out is a 400 `invalid_cursor`.

Also available in: API [`GET /signatures`](https://openemail.uk/docs/api/reference/settings#get-signatures); TypeScript [`signatures.list()`](https://openemail.uk/docs/sdk/reference/signatures#list); Python [`signatures.list()`](https://openemail.uk/docs/python/reference/signatures#list); Ruby [`signatures.list`](https://openemail.uk/docs/ruby/reference/signatures#list); PHP [`signatures->list`](https://openemail.uk/docs/php/reference/signatures#list); Go [`Signatures.List`](https://openemail.uk/docs/go/reference/signatures#list); Java [`signatures().list`](https://openemail.uk/docs/java/reference/signatures#list); CLI [`openemail signatures list`](https://openemail.uk/docs/cli/reference/signatures#signatures-list).

### `Signatures.ListAllAsync`

Collect every signature into one list

```csharp
Task<IReadOnlyList<JsonObject>> ListAllAsync(
    string? address = null,
    int? limit = null,
    string? cursor = null,
    string? apiKey = null,
    CancellationToken cancellationToken = default)
```

Walks every page of `Signatures.ListAsync` and returns all signatures in one list, sorted by address and then oldest first. One request per page. Give `address:` to collect the signatures of one address or catch-all.

Scopes: `settings:read`.

**Parameters**

- `address` (`string?`): One address, or `*@example.com` for a catch-all. Left out, every address is collected.
- `limit` (`int?`): Page size for each request, from 1 to 100. The server defaults to 25.
- `cursor` (`string?`): Starts the walk after this cursor instead of the first page.
- `apiKey` (`string?`): Overrides the client's API key for every page of this walk.
- `cancellationToken` (`CancellationToken`): Cancels the request in flight and the walk with it.

**Returns**

A list of signature objects holding every signature.

**Example**

```csharp
var signatures = await client.Signatures.ListAllAsync(address: "hello@example.com");
var brief = signatures.FirstOrDefault(signature => (string?)signature["name"] == "Short");

if (brief is not null)
{
    await client.Emails.SendAsync(new Body
    {
        ["from"] = "hello@example.com",
        ["to"] = "ada@example.com",
        ["subject"] = "Quick note",
        ["text"] = "See you on Thursday.",
        ["signatureId"] = (string?)brief["id"],
    });
}
```

**Notes**

- If any page fails, the exception is thrown and the signatures already fetched are discarded.

Also available in: API [`GET /signatures`](https://openemail.uk/docs/api/reference/settings#get-signatures); TypeScript [`signatures.listAll()`](https://openemail.uk/docs/sdk/reference/signatures#listAll); Python [`signatures.list_all()`](https://openemail.uk/docs/python/reference/signatures#listAll); Ruby [`signatures.list_all`](https://openemail.uk/docs/ruby/reference/signatures#listAll); PHP [`signatures->listAll`](https://openemail.uk/docs/php/reference/signatures#listAll); Go [`Signatures.ListAll`](https://openemail.uk/docs/go/reference/signatures#listAll); Java [`signatures().listAll`](https://openemail.uk/docs/java/reference/signatures#listAll).

### `Signatures.IterateAsync`

Stream the signatures one at a time

```csharp
IAsyncEnumerable<JsonObject> IterateAsync(
    string? address = null,
    int? limit = null,
    string? cursor = null,
    string? apiKey = null,
    CancellationToken cancellationToken = default)
```

Returns an `IAsyncEnumerable<JsonObject>` that yields signatures one at a time, sorted by address and then oldest first, and requests the next page only once the current one is used up. Nothing is fetched until the loop starts, and breaking out of the `await foreach` stops the requests.

Scopes: `settings:read`.

**Parameters**

- `address` (`string?`): One address, or `*@example.com` for a catch-all. Left out, every address is walked.
- `limit` (`int?`): Page size for each request, from 1 to 100. The server defaults to 25.
- `cursor` (`string?`): Starts the walk after this cursor instead of the first page.
- `apiKey` (`string?`): Overrides the client's API key for every page of this walk.
- `cancellationToken` (`CancellationToken`): Cancels the request in flight and the walk with it.

**Returns**

An `IAsyncEnumerable<JsonObject>` that yields one signature per step.

**Example**

```csharp
await foreach (var signature in client.Signatures.IterateAsync())
{
    if ((bool?)signature["isDefault"] == true)
    {
        Console.WriteLine($"{signature["address"]} signs new mail with {signature["name"]}");
    }
}
```

**Notes**

- The walk is lazy, so an abandoned loop costs only the pages you consumed.

Also available in: API [`GET /signatures`](https://openemail.uk/docs/api/reference/settings#get-signatures); TypeScript [`signatures.iterate()`](https://openemail.uk/docs/sdk/reference/signatures#iterate); Python [`signatures.iterate()`](https://openemail.uk/docs/python/reference/signatures#iterate); Ruby [`signatures.iterate`](https://openemail.uk/docs/ruby/reference/signatures#iterate); PHP [`signatures->iterate`](https://openemail.uk/docs/php/reference/signatures#iterate); Go [`Signatures.Iterate`](https://openemail.uk/docs/go/reference/signatures#iterate); Java [`signatures().iterate`](https://openemail.uk/docs/java/reference/signatures#iterate).

### `Signatures.GetAsync`

Read one signature by id

```csharp
Task<JsonObject> GetAsync(
    string id,
    string? apiKey = null,
    CancellationToken cancellationToken = default)
```

Looks up a single signature and returns it in the same shape as a row of `Signatures.ListAsync`: the address it belongs to, its name, its HTML and whether it is the default for new mail, for replies and forwards, for both or for neither.

Scopes: `settings:read`.

**Parameters**

- `id` (`string`, required): Signature id, which starts with `sig_`.
- `apiKey` (`string?`): Overrides the client's API key for this call only.
- `cancellationToken` (`CancellationToken`): Cancels the request.

**Returns**

A `JsonObject` with `id`, `address`, `name`, `html`, `isDefault`, `isReplyDefault`, `createdAt` and `updatedAt`.

**Example**

```csharp
try
{
    var signature = await client.Signatures.GetAsync("sig_8f2c1a9b7d3e4f60a1b2c3d4");

    Console.WriteLine($"{signature["address"]} {signature["name"]}: {signature["html"]}");
}
catch (OpenEmailApiException error) when (error.IsNotFound)
{
    Console.WriteLine("No such signature");
}
```

**Notes**

- A missing signature throws an `OpenEmailApiException` whose `IsNotFound` is true and whose `Code` is `resource_not_found`. So does one on an address a narrowed key does not hold.

Also available in: API [`GET /signatures/{id}`](https://openemail.uk/docs/api/reference/settings#get-signatures-id); TypeScript [`signatures.get()`](https://openemail.uk/docs/sdk/reference/signatures#get); Python [`signatures.get()`](https://openemail.uk/docs/python/reference/signatures#get); Ruby [`signatures.get`](https://openemail.uk/docs/ruby/reference/signatures#get); PHP [`signatures->get`](https://openemail.uk/docs/php/reference/signatures#get); Go [`Signatures.Get`](https://openemail.uk/docs/go/reference/signatures#get); Java [`signatures().get`](https://openemail.uk/docs/java/reference/signatures#get); CLI [`openemail signatures get`](https://openemail.uk/docs/cli/reference/signatures#signatures-get).

### `Signatures.CreateAsync`

Add a signature to an address

```csharp
Task<JsonObject> CreateAsync(
    IReadOnlyDictionary<string, object?> body,
    string? apiKey = null,
    CancellationToken cancellationToken = default)
```

Adds a signature to one address, or to a catch-all with `*@example.com`, and returns it as it is stored. `name` is what the app calls it and is unique on its address, whatever the case, so a second `Work` on the same address is a 409 `signature_name_taken`. `html` is sanitised the way outgoing mail is and has to keep some text or an image, so the stored HTML can differ from what you sent.

The first signature of an address becomes its default for new mail and for replies and forwards, unless `isDefault` or `isReplyDefault` says `false`. A later signature becomes a default only when you ask, and then takes that place from the signature that held it. An address holds at most 50 signatures, and the call past that is a 422 `signature_limit_reached`.

The address has to be one of the workspace, or a catch-all on a verified domain here with its catch-all on.

Scopes: `settings:write`.

**Parameters**

- `address` (`string`, required): The address the signature is for, such as `hello@example.com`, or `*@example.com` for the catch-all of a domain.
- `name` (`string`, required): What the signature is called, trimmed, 1 to 80 characters. Unique on its address, whatever the case.
- `html` (`string`, required): The signature as HTML, at most 150,000 characters before and after sanitising. It has to keep some text or an image.
- `isDefault` (`bool`): `true` makes it the signature of new mail from the address. Left out, only the first signature of an address becomes that.
- `isReplyDefault` (`bool`): `true` makes it the signature of replies and forwards from the address. Left out, only the first signature of an address becomes that.
- `apiKey` (`string?`): Overrides the client's API key for this call only.
- `cancellationToken` (`CancellationToken`): Cancels the request.

**Returns**

A `JsonObject` with the new `id`, the trimmed `name`, the sanitised `html`, `isDefault` and `isReplyDefault`.

**Example**

```csharp
try
{
    var signature = await client.Signatures.CreateAsync(new Body
    {
        ["address"] = "hello@example.com",
        ["name"] = "Short",
        ["html"] = "<p>Ada<br>Acme Ltd</p>",
        ["isReplyDefault"] = true,
    });

    Console.WriteLine($"Created {signature["id"]}, default for replies: {signature["isReplyDefault"]}");
}
catch (OpenEmailApiException error) when (error.IsConflict)
{
    Console.WriteLine($"That name is taken on the address: {error.Code}");
}
```

**Notes**

- The SDK does not retry a create after a network failure. If you retry by hand after a lost response, a 409 `signature_name_taken` means the first attempt succeeded.
- A key or an app limited to particular addresses or domains can only add to an address it holds, and to a catch-all only when it holds the domain whole. Anything else is a 422 `capability_unsupported`.
- `Signatures.CopyAsync` puts the same signature on other addresses.

Also available in: API [`POST /signatures`](https://openemail.uk/docs/api/reference/settings#post-signatures); TypeScript [`signatures.create()`](https://openemail.uk/docs/sdk/reference/signatures#create); Python [`signatures.create()`](https://openemail.uk/docs/python/reference/signatures#create); Ruby [`signatures.create`](https://openemail.uk/docs/ruby/reference/signatures#create); PHP [`signatures->create`](https://openemail.uk/docs/php/reference/signatures#create); Go [`Signatures.Create`](https://openemail.uk/docs/go/reference/signatures#create); Java [`signatures().create`](https://openemail.uk/docs/java/reference/signatures#create); CLI [`openemail signatures create`](https://openemail.uk/docs/cli/reference/signatures#signatures-create).

### `Signatures.UpdateAsync`

Rename a signature, rewrite it or change what it is the default for

```csharp
Task<JsonObject> UpdateAsync(
    string id,
    IReadOnlyDictionary<string, object?> patch,
    string? apiKey = null,
    CancellationToken cancellationToken = default)
```

Changes a signature and returns it as it is stored. Send any of `name`, `html`, `isDefault` and `isReplyDefault`: a field left out stays as it is, and a patch with none of them is a 422.

`["isDefault"] = true` makes it the signature of new mail from its address in place of the one that was. `["isDefault"] = false` takes that away when this signature held it, so new mail from the address goes out with no signature until another one is chosen. `isReplyDefault` does the same for replies and forwards. The two are independent, so one signature can sign new mail and another, shorter one the replies.

A new name another signature of the address already has, compared without case, is a 409 `signature_name_taken`. The HTML is sanitised again and has to keep some text or an image. A message that is already scheduled picks up the new HTML when it goes out.

Scopes: `settings:write`.

**Parameters**

- `id` (`string`, required): Signature id, which starts with `sig_`.
- `name` (`string`): New name, trimmed, 1 to 80 characters. Left out, the name stays.
- `html` (`string`): New HTML, at most 150,000 characters before and after sanitising. Left out, the HTML stays.
- `isDefault` (`bool`): `true` makes it the default for new mail, `false` takes that away when it held it. Left out, nothing changes.
- `isReplyDefault` (`bool`): `true` makes it the default for replies and forwards, `false` takes that away when it held it. Left out, nothing changes.
- `apiKey` (`string?`): Overrides the client's API key for this call only.
- `cancellationToken` (`CancellationToken`): Cancels the request.

**Returns**

A `JsonObject` with the unchanged `id` and `address` and the new `name`, `html`, `isDefault` and `isReplyDefault`.

**Example**

```csharp
var saved = await client.Signatures.UpdateAsync("sig_8f2c1a9b7d3e4f60a1b2c3d4", new Body { ["isDefault"] = true });

Console.WriteLine($"{saved["name"]} now signs new mail from {saved["address"]}");

await client.Signatures.UpdateAsync("sig_8f2c1a9b7d3e4f60a1b2c3d4", new Body
{
    ["name"] = "Work",
    ["html"] = "<p>Ada Lovelace<br>Acme Ltd</p>",
});
```

**Notes**

- The SDK retries this call after a network failure, since the same patch sent twice leaves the same signature.
- `Settings.UpdateAsync` with an address still takes `signature`: it rewrites the HTML of the default for new mail, and adds a signature called `Signature` when the address has no default.

Also available in: API [`PATCH /signatures/{id}`](https://openemail.uk/docs/api/reference/settings#patch-signatures-id); TypeScript [`signatures.update()`](https://openemail.uk/docs/sdk/reference/signatures#update); Python [`signatures.update()`](https://openemail.uk/docs/python/reference/signatures#update); Ruby [`signatures.update`](https://openemail.uk/docs/ruby/reference/signatures#update); PHP [`signatures->update`](https://openemail.uk/docs/php/reference/signatures#update); Go [`Signatures.Update`](https://openemail.uk/docs/go/reference/signatures#update); Java [`signatures().update`](https://openemail.uk/docs/java/reference/signatures#update); CLI [`openemail signatures update`](https://openemail.uk/docs/cli/reference/signatures#signatures-update).

### `Signatures.DeleteAsync`

Delete a signature

```csharp
Task<JsonObject> DeleteAsync(
    string id,
    string? apiKey = null,
    CancellationToken cancellationToken = default)
```

Deletes a signature for good. When it was a default, that default is left empty, so mail it would have signed goes out with no signature until another one is chosen with `Signatures.UpdateAsync`. A scheduled message that named it with `signatureId` carries the default of its address instead. There is no undo.

Scopes: `settings:write`.

**Parameters**

- `id` (`string`, required): Signature id, which starts with `sig_`.
- `apiKey` (`string?`): Overrides the client's API key for this call only.
- `cancellationToken` (`CancellationToken`): Cancels the request.

**Returns**

A `JsonObject`, `{ object: 'signature', id, address, deleted: true }`.

**Example**

```csharp
var removed = await client.Signatures.DeleteAsync("sig_8f2c1a9b7d3e4f60a1b2c3d4");

if ((bool?)removed["deleted"] == true)
{
    Console.WriteLine($"Removed from {removed["address"]}");
}
```

**Notes**

- The SDK does not retry a delete. A 404 on your own second attempt after a lost response means the first one worked.

Also available in: API [`DELETE /signatures/{id}`](https://openemail.uk/docs/api/reference/settings#delete-signatures-id); TypeScript [`signatures.delete()`](https://openemail.uk/docs/sdk/reference/signatures#delete); Python [`signatures.delete()`](https://openemail.uk/docs/python/reference/signatures#delete); Ruby [`signatures.delete`](https://openemail.uk/docs/ruby/reference/signatures#delete); PHP [`signatures->delete`](https://openemail.uk/docs/php/reference/signatures#delete); Go [`Signatures.Delete`](https://openemail.uk/docs/go/reference/signatures#delete); Java [`signatures().delete`](https://openemail.uk/docs/java/reference/signatures#delete); CLI [`openemail signatures delete`](https://openemail.uk/docs/cli/reference/signatures#signatures-delete).

### `Signatures.CopyAsync`

Copy a signature to other addresses

```csharp
Task<IReadOnlyList<JsonObject>> CopyAsync(
    string id,
    IReadOnlyDictionary<string, object?> body,
    string? apiKey = null,
    CancellationToken cancellationToken = default)
```

Puts a copy of a signature on up to 500 other addresses or catch-alls, as Copy to other addresses does in the app, and returns the copies. An address that already has a signature with the same name, whatever the case, gets its HTML replaced, so copying again after an edit brings every copy up to date. Any other address gets a new signature with that name.

A copy becomes the default for new mail where `isDefault` is `true` and the default for replies and forwards where `isReplyDefault` is `true`. On an address that had no signature at all it becomes both unless you say `false`. Left out, the defaults of the other addresses stay as they are.

The address the signature is already on is skipped. Each copy is its own signature from then on, with its own id: editing the original later changes no copy until you copy again.

Scopes: `settings:write`.

**Parameters**

- `id` (`string`, required): The signature to copy.
- `addresses` (`IEnumerable<string>`, required): 1 to 500 addresses to copy it to. Each is one address or `*@example.com` for a catch-all.
- `isDefault` (`bool`): `true` makes each copy the default for new mail on its address.
- `isReplyDefault` (`bool`): `true` makes each copy the default for replies and forwards on its address.
- `apiKey` (`string?`): Overrides the client's API key for this call only.
- `cancellationToken` (`CancellationToken`): Cancels the request.

**Returns**

A list of signature objects, one copy for each address, in the order given.

**Example**

```csharp
var copies = await client.Signatures.CopyAsync("sig_8f2c1a9b7d3e4f60a1b2c3d4", new Body
{
    ["addresses"] = new[] { "sales@example.com", "support@example.com" },
    ["isDefault"] = true,
});

foreach (var copy in copies)
{
    Console.WriteLine($"{copy["address"]} has {copy["id"]}, default for new mail: {copy["isDefault"]}");
}
```

**Notes**

- The copies are written one address at a time. When an address is full, the call fails with 422 `signature_limit_reached` and the addresses before it keep their copy, so the same call can be sent again once there is room.
- The SDK retries this call after a network failure, since copying twice leaves the same signatures.
- A key or an app limited to particular addresses or domains can only copy to addresses it holds. One it does not hold fails the whole call with 422 `capability_unsupported` before anything is written.

Also available in: API [`POST /signatures/{id}/copy`](https://openemail.uk/docs/api/reference/settings#post-signatures-id-copy); TypeScript [`signatures.copy()`](https://openemail.uk/docs/sdk/reference/signatures#copy); Python [`signatures.copy()`](https://openemail.uk/docs/python/reference/signatures#copy); Ruby [`signatures.copy`](https://openemail.uk/docs/ruby/reference/signatures#copy); PHP [`signatures->copy`](https://openemail.uk/docs/php/reference/signatures#copy); Go [`Signatures.Copy`](https://openemail.uk/docs/go/reference/signatures#copy); Java [`signatures().copy`](https://openemail.uk/docs/java/reference/signatures#copy); CLI [`openemail signatures copy`](https://openemail.uk/docs/cli/reference/signatures#signatures-copy).
