client.Contacts
この名前空間のすべてのメソッドの、シグネチャ、パラメーター、戻り値、例。
メソッド
The workspace address book: the contacts somebody saved and the ones the app composer recorded, everyone seen in mail beside them, and for each person their audiences, photo, blocking, conversations and activity.
Contacts.ListAsyncContacts.ListAllAsyncContacts.IterateAsyncContacts.GetAsyncContacts.CreateAsyncContacts.UpdateAsyncContacts.DeleteAsyncContacts.SetAudiencesAsyncContacts.ListPeopleAsyncContacts.ListAllPeopleAsyncContacts.IteratePeopleAsyncContacts.SaveAsyncContacts.DeleteManyAsyncContacts.SetPhotoAsyncContacts.RemovePhotoAsyncContacts.BlockAsyncContacts.UnblockAsyncContacts.ListThreadsAsyncContacts.ListAllThreadsAsyncContacts.IterateThreadsAsyncContacts.ActivityAsyncContacts.ListEventsAsyncContacts.ListAllEventsAsyncContacts.IterateEventsAsyncContacts.ListCardsAsyncContacts.ListAllCardsAsyncContacts.IterateCardsAsyncContacts.GetCardAsyncContacts.CreateCardAsyncContacts.UpdateCardAsyncContacts.DeleteCardAsyncContacts.ImportVcfAsyncContacts.ListImportsAsyncContacts.ListAllImportsAsyncContacts.IterateImportsAsyncContacts.GetImportAsyncContacts.UndoImportAsync
Contacts.ListAsync
List the workspace contacts, most recently seen first
Task<Page> ListAsync( string? source = null, string? q = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns one page of the workspace address book, ordered by lastSeenAt with the most recent first and contacts that have never been mailed last. source says where a row came from: manual for a contact somebody saved, in the app or through Contacts.CreateAsync, and auto for an address recorded when a member sent mail to it from the app composer. A saved contact stays manual when it is mailed later.
source: narrows the page to one origin, so source: 'manual' is the contacts somebody saved on purpose and source: 'auto' the ones the composer recorded. q: searches the name and the address.
This lists saved contacts only. Contacts.ListPeopleAsync lists everyone the Contacts page in the app shows, the addresses seen in mail included, with thread counts.
Paging is keyset. limit: takes 1 to 200 and defaults to 50, and nextCursor goes back as cursor: while hasMore is true. Never build a cursor yourself.
Contacts belong to the whole workspace rather than to any one address, so a key limited to particular addresses or domains reads and writes the same book as every other key. An app connected by a member who reaches only some addresses is refused with 422 capability_unsupported on addressAllowlist, on every contacts, audiences and broadcasts route.
パラメーター
sourcestring?manual,autoorform. Leave it out for the whole book.qstring?Searches the name and the address, up to 200 characters. When nothing matches exactly on the first page, close spellings are returned instead, and the pages that follow keep matching the same way.
limitint?Rows per page, a whole number from 1 to 200. The server defaults to 50.
cursorstring?The
nextCursorfrom the previous page. Never build one yourself.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A Page of contact objects, with items, hasMore and nextCursor. Each contact has email, name, source, notes, photoUrl and lastSeenAt.
例
var page = await client.Contacts.ListAsync(source: "manual", limit: 50); if (page.HasMore){ var next = await client.Contacts.ListAsync(source: "manual", limit: 50, cursor: page.NextCursor); Console.WriteLine($"{next.Count} more");}注意事項
Mail sent through this API adds no contacts. Only sends from the app composer record recipients, and
Contacts.CreateAsyncis the way to add one deliberately.Every member of the workspace reads and writes the same book, so a contact saved by one person is visible to the rest.
A contact that has never been mailed has
lastSeenAtnull and sorts last, after every contact with a date.Addresses are stored lower cased.
ほかの提供先
- API
GET /contacts- TypeScript
contacts.list()- Python
contacts.list()- Ruby
contacts.list- PHP
contacts->list- Go
Contacts.List- Java
contacts().list- CLI
openemail contacts list
Contacts.ListAllAsync
Collect the whole address book into one object
Task<IReadOnlyList<JsonObject>> ListAllAsync( string? source = null, string? q = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Follows nextCursor from page to page and returns every contact in the workspace, most recently seen first and never-mailed contacts last. It takes the same source: and q: filters as Contacts.ListAsync.
Everything is held in memory before the call returns, and an address book grows with every recipient the composer records. Prefer Contacts.IterateAsync when you can stop early. limit: sets the page size of each request, not the total.
パラメーター
sourcestring?manual,autoorform. Leave it out for the whole book.qstring?Searches the name and the address, up to 200 characters. When nothing matches exactly on the first page, close spellings are returned instead, and the pages that follow keep matching the same way.
limitint?Page size per request, from 1 to 200, defaulting to 50 on the server.
cursorstring?A cursor from an earlier page to start after.
apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request.
戻り値
A list of contact objects holding every contact across all pages.
例
var saved = await client.Contacts.ListAllAsync(source: "manual", limit: 200); Console.WriteLine($"{saved.Count} contacts saved on purpose");Console.WriteLine($"{string.Join(Environment.NewLine, saved.Select(row => row?["email"]))}");注意事項
A failure on any page throws out of the whole call, and the contacts already fetched are discarded.
ほかの提供先
- API
GET /contacts- TypeScript
contacts.listAll()- Python
contacts.list_all()- Ruby
contacts.list_all- PHP
contacts->listAll- Go
Contacts.ListAll- Java
contacts().listAll
Contacts.IterateAsync
Stream the address book one contact at a time
IAsyncEnumerable<JsonObject> IterateAsync( string? source = null, string? q = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns an IAsyncEnumerable<JsonObject> that yields contacts one at a time, most recently seen 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.
パラメーター
sourcestring?manual,autoorform. Leave it out for the whole book.qstring?Searches the name and the address, up to 200 characters. When nothing matches exactly on the first page, close spellings are returned instead, and the pages that follow keep matching the same way.
limitint?Page size per request, from 1 to 200, defaulting to 50 on the server.
cursorstring?A cursor from an earlier page to start after.
apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request.
戻り値
An IAsyncEnumerable<JsonObject> that yields one contact per step.
例
await foreach (var contact in client.Contacts.IterateAsync(source: "auto")){ if (contact["lastSeenAt"] is null) { break; } Console.WriteLine($"{contact["email"]} {contact["lastSeenAt"]}");}注意事項
The generator is lazy, so an abandoned loop costs only the pages you consumed.
ほかの提供先
- API
GET /contacts- TypeScript
contacts.iterate()- Python
contacts.iterate()- Ruby
contacts.iterate- PHP
contacts->iterate- Go
Contacts.Iterate- Java
contacts().iterate
Contacts.GetAsync
Read one contact by email address
Task<JsonObject> GetAsync( string email, string? apiKey = null, CancellationToken cancellationToken = default)Looks up a contact by address in the workspace address book. The address is trimmed and lower cased before the lookup, so [email protected] finds [email protected], and the SDK URL encodes it for the path.
A 404 means only that the address is not in the book. It says nothing about whether mail has been exchanged with it, since received mail never creates contacts.
パラメーター
emailstring必須The contact's address, matched case insensitively.
apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject with email, name, source, notes, photoUrl and lastSeenAt, plus audiences, every audience the contact is in as an object with id, name and builtin. builtin is default on the audience every contact belongs to and null on one somebody created. A key that also holds forms:read gets signUps, what this address sent through sign-up forms, newest first and at most 20. Each is an object with id, formId, formName, status (pending or added), answers, sourceUrl, createdAt and confirmedAt.
例
try{ var contact = await client.Contacts.GetAsync("[email protected]");}catch (OpenEmailApiException error) when (error.IsNotFound){ Console.WriteLine("Not in the address book");}注意事項
nameis null for an address recorded automatically without a display name, andnotesis free text somebody set in the app or throughContacts.UpdateAsync.The address is the contact's identity here and on every other contacts route. There is no id in the public contract.
ほかの提供先
- API
GET /contacts/{email}- TypeScript
contacts.get()- Python
contacts.get()- Ruby
contacts.get- PHP
contacts->get- Go
Contacts.Get- Java
contacts().get- CLI
openemail contacts get
Contacts.CreateAsync
Save a contact in the workspace address book
Task<JsonObject> CreateAsync( IReadOnlyDictionary<string, object?> body, string? apiKey = null, CancellationToken cancellationToken = default)Adds one address to the workspace address book and returns the saved row. email is trimmed and lower cased before it is stored, so [email protected] and [email protected] are the same contact.
The contact is saved with source set to manual, the same value a contact typed into the app carries, and it joins the default audience as it is written. Every contact is in that audience for as long as it exists, so there is nothing to add afterwards. Name audiences of your own in audienceIds to put it in them in the same call, or add it later with Audiences.AddContactAsync. Sending audienceIds also requires the audiences:write scope, since it writes memberships as well as a contact.
An address can be in the book once. A second create for an address that is already there is refused with 409 contact_exists rather than merged, so a retry cannot quietly overwrite a name somebody edited in the app. Read the existing row with Contacts.GetAsync and change it with Contacts.UpdateAsync.
パラメーター
emailstring必須The address to save, trimmed and lower cased before it is stored.
namestringDisplay name. Leave it out to save the contact without one.
notesstringFree text kept with the contact and shown beside it in the app.
audienceIdsIEnumerable<string>Up to 25 audience ids to put the new contact in. The default audience is joined whether or not it is named. When this is present the key also needs
audiences:write, or the call is refused with 403 before anything is saved.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject with email, name, source as manual, notes and lastSeenAt, which is null until mail goes to the address from the app composer, plus audiences, every audience the contact is now in, the default one included.
例
try{ var contact = await client.Contacts.CreateAsync(new Body { ["email"] = "[email protected]", ["name"] = "Grace Hopper", ["notes"] = "Met at the compiler workshop.", ["audienceIds"] = new[] { "aud_9f2c4b7e1a0d63d84c5f2e7b" }, }); Console.WriteLine($"Saved {contact["email"]} in {contact["audiences"]?.AsArray().Count} audiences");}catch (OpenEmailApiException error) when (error.IsConflict){ Console.WriteLine("Already in the book, so change it with contacts->update");}注意事項
The SDK does not retry a create after a network failure. If you retry by hand after a lost response, a 409
contact_existsmeans the first attempt landed.Contacts belong to the workspace, so the contact this creates is the one every member and every other key sees.
An id in
audienceIdsthat is not an audience of this workspace fails the whole create. Nothing is saved.
ほかの提供先
- API
POST /contacts- TypeScript
contacts.create()- Python
contacts.create()- Ruby
contacts.create- PHP
contacts->create- Go
Contacts.Create- Java
contacts().create- CLI
openemail contacts create
Contacts.UpdateAsync
Change a contact's name or notes
Task<JsonObject> UpdateAsync( string email, IReadOnlyDictionary<string, object?> patch, string? apiKey = null, CancellationToken cancellationToken = default)Changes the fields you send and leaves the rest alone. A key you leave out keeps its stored value, and an explicit null clears it, so new Body { ["notes"] = null } empties the notes while [] changes nothing.
The address cannot be changed. It is the contact's identity, its path segment and the unique key of the book, so moving a contact to a new address is a Contacts.DeleteAsync and a Contacts.CreateAsync, and that new contact starts with no audience membership beyond the default one.
source and lastSeenAt are the server's to set and are not accepted here. A contact recorded automatically stays auto after you give it a name.
パラメーター
emailstring必須The contact's address, matched case insensitively.
namestringNew display name. Null clears it.
notesstringNew notes. Null clears them.
apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject for the contact as it stands after the change, with audiences alongside it.
例
var contact = await client.Contacts.UpdateAsync("[email protected]", new Body { ["name"] = "Grace Hopper", ["notes"] = null }); Console.WriteLine($"{contact["name"]}, notes {(contact["notes"] is null ? "cleared" : "kept")}");注意事項
The SDK retries this call after a network failure, since the same patch sent twice leaves the same contact.
An address that is not in the book is a 404, the same as
Contacts.GetAsync.Audience membership is not touched here. Use
Contacts.SetAudiencesAsyncto set the whole list, orAudiences.AddContactAsyncandAudiences.RemoveContactAsyncfor one audience.
ほかの提供先
Contacts.DeleteAsync
Delete somebody from the contacts and hide the address
Task<JsonObject> DeleteAsync( string email, string? apiKey = null, CancellationToken cancellationToken = default)Does what Delete does on the Contacts page in the app. A saved contact goes with its notes, its photo and every audience it was in, the default one included. The address is then hidden: Contacts.ListPeopleAsync leaves it out, and mail sent to it from the app composer no longer records it as a contact. The address can be one that was only ever seen in mail, which is how you take somebody off the people list, and wasSaved says which it was.
Nothing else moves: the mail exchanged with the address stays in the mailbox, and the address can still be written to. There is no undo. Contacts.CreateAsync or Contacts.SaveAsync afterwards brings the address back as a new contact with no name, no notes and no membership beyond the default audience.
パラメーター
emailstring必須The contact's address, matched case insensitively.
apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject with object set to contact, email, deleted set to true and wasSaved.
例
var removed = await client.Contacts.DeleteAsync("[email protected]"); Console.WriteLine($"{removed["email"]}{((bool?)removed["wasSaved"] == true ? " was a saved contact" : " was only seen in mail")} and is now hidden");注意事項
An address that is not in the book is no longer a 404: it is hidden and answers with
wasSavedfalse. Something that is not an address is a 422invalid_contact.The SDK does not retry a delete, though a second attempt is harmless: it answers with
wasSavedfalse.Contacts.DeleteManyAsyncdeletes up to 200 addresses in one call.
ほかの提供先
Contacts.SetAudiencesAsync
Set exactly which audiences a contact is in
Task<JsonObject> SetAudiencesAsync( string email, IReadOnlyDictionary<string, object?> body, string? apiKey = null, CancellationToken cancellationToken = default)Makes the contact's audiences match the list you send, the way the audience picker on a contact does in the app. The contact joins every listed audience it is not in yet and leaves every other one, in one transaction, and memberships it keeps keep their addedAt.
The default audience is always kept, whether or not you name it, so new Body { ["audienceIds"] = Array.Empty<string>() } leaves the contact in the default audience alone. To add or remove one audience without restating the rest, use Audiences.AddContactAsync or Audiences.RemoveContactAsync.
The address is trimmed and lower cased, the SDK URL encodes it for the path, and it has to be a contact already: an address that is not in the book is a 404 contact_not_found on email. Create it with Contacts.CreateAsync, which takes audienceIds too. An id that is not an audience of this workspace is a 404 audience_not_found on audienceIds, and nothing is changed.
パラメーター
emailstring必須The contact's address, matched case insensitively.
audienceIdsIEnumerable<string>必須Every audience the contact should be in, up to 100 ids. A repeated id counts once. More than 100 is a 422
invalid_parameteronaudienceIds, and an empty id is the same error on that entry, such asaudienceIds.0.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject for the contact as it stands after the change, with audiences, every audience the contact is now in as an object with id, name and builtin, the default one included.
例
var contact = await client.Contacts.SetAudiencesAsync("[email protected]", new Body{ ["audienceIds"] = new[] { "aud_9f2c4b7e1a0d63d84c5f2e7b", "aud_1c4e7a9b2d0f36e85a7c1b4d" },}); foreach (var audience in contact["audiences"]?.AsArray() ?? []){ Console.WriteLine($"{audience?["name"]}{((string?)audience?["builtin"] == "default" ? ", everyone" : "")}");}注意事項
audiences:writeis the only scope checked, because this writes memberships rather than the contact.Safe to replay: sending the same list again changes nothing. The SDK retries it after a network failure.
Read the current list with
Contacts.GetAsyncfirst when you mean to add one audience to what the contact already has, or useAudiences.AddContactAsync.
ほかの提供先
Contacts.ListPeopleAsync
List everyone on the Contacts page, saved or seen in mail
Task<PeoplePage> ListPeopleAsync( string? q = null, string? email = null, string? sort = null, bool? blocked = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns one page of the people the Contacts page in the app lists: the saved contacts, and every address seen in mail as the sender or a recipient of a thread's newest message. Each row says whether it is saved, how many threads it shares with the mailbox and when mail last moved (lastAt). A person seen in mail and saved is one row. Contacts.ListAsync is the saved contacts alone.
The addresses seen in mail are included only when the key also holds threads:read, because they are read out of the mail. Without it the page holds the saved contacts and seen is false. Deleted addresses and the mailbox's own addresses are never listed.
sort: is recent, newest mail first and saved contacts never seen in mail after them, name, by name or else by address, ignoring case, or threads, most threads first. blockedBy on each row names the workspace blocklist rule that blocks it, and blocked: true narrows the page to those rows.
Paging is keyset. limit: takes 1 to 100 and defaults to 25, and nextCursor goes back as cursor:, with the same sort:, q: and blocked:, while hasMore is true.
パラメーター
qstring?Searches names, addresses and notes, up to 200 characters. When nothing matches exactly on the first page, close spellings are returned instead.
emailstring?One address only, matched case insensitively: the way to read one person's thread count and last mail.
sortstring?recent(the default),nameorthreads, also inOpenEmail\Constants\PeopleSorts.blockedbool?truefor only the people the workspace blocklist blocks, whole-domain rules included.limitint?Rows per page, 1 to 100. The server defaults to 25.
cursorstring?The
nextCursorfrom the previous page. Never build one yourself.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A PeoplePage with items, hasMore, nextCursor and seen. Each person is an object with email, displayEmail, name, saved, source, notes, photoUrl, threads, lastAt, createdAt, updatedAt and blockedBy.
例
using OpenEmail.Constants; var people = await client.Contacts.ListPeopleAsync(sort: PeopleSorts.Threads, limit: 50); if (!people.Seen){ Console.WriteLine("Saved contacts only, since this key cannot read the mail");}注意事項
emailis lower cased and is what every other contacts method takes.displayEmailkeeps the capitals the newest message wrote.A malformed or stale cursor is a 400
invalid_cursor. Start again without one.A key limited to particular addresses or domains gets the saved contacts alone, with
seenfalse, even when it holdsthreads:read, because the addresses seen in mail would be read from the mail of every address in the workspace.
ほかの提供先
Contacts.ListAllPeopleAsync
Collect everyone on the Contacts page into one object
Task<IReadOnlyList<JsonObject>> ListAllPeopleAsync( string? q = null, string? email = null, string? sort = null, bool? blocked = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Follows nextCursor from page to page and returns every person Contacts.ListPeopleAsync would list, in the same order and with the same filters. It is how you count the people a blocklist blocks: (await client.Contacts.ListAllPeopleAsync(blocked: true)).Count.
Everything is held in memory before the call returns, and a busy mailbox has seen a great many addresses. Prefer Contacts.IteratePeopleAsync when you can stop early.
パラメーター
qstring?Searches names, addresses and notes, up to 200 characters. When nothing matches exactly on the first page, close spellings are returned instead.
emailstring?One address only, matched case insensitively: the way to read one person's thread count and last mail.
sortstring?recent(the default),nameorthreads.blockedbool?truefor only the people the workspace blocklist blocks, whole-domain rules included.limitint?Page size per request, from 1 to 100, defaulting to 25 on the server.
cursorstring?A cursor from an earlier page to start after.
apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request.
戻り値
A list of person objects holding every person across all pages.
例
var blocked = await client.Contacts.ListAllPeopleAsync(blocked: true, limit: 100); Console.WriteLine($"{blocked.Count} people are blocked"); foreach (var person in blocked){ Console.WriteLine($"{person["email"]} by {person["blockedBy"]?["rule"]} in {person["blockedBy"]?["list"]}");}注意事項
A failure on any page throws out of the whole call, and the people already fetched are discarded.
seenis not reported here. Read one page withContacts.ListPeopleAsyncto learn whether the key reads the people seen in mail.
ほかの提供先
Contacts.IteratePeopleAsync
Stream everyone on the Contacts page one person at a time
IAsyncEnumerable<JsonObject> IteratePeopleAsync( string? q = null, string? email = null, string? sort = null, bool? blocked = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns an IAsyncEnumerable<JsonObject> that yields the people Contacts.ListPeopleAsync lists, one at a time, 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.
パラメーター
qstring?Searches names, addresses and notes, up to 200 characters. When nothing matches exactly on the first page, close spellings are returned instead.
emailstring?One address only, matched case insensitively: the way to read one person's thread count and last mail.
sortstring?recent(the default),nameorthreads.blockedbool?truefor only the people the workspace blocklist blocks, whole-domain rules included.limitint?Page size per request, from 1 to 100, defaulting to 25 on the server.
cursorstring?A cursor from an earlier page to start after.
apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request.
戻り値
An IAsyncEnumerable<JsonObject> that yields one person per step.
例
await foreach (var person in client.Contacts.IteratePeopleAsync(sort: "threads")){ if ((int?)person["threads"] < 5) { break; } if ((bool?)person["saved"] != true) { await client.Contacts.SaveAsync(person["email"]!.GetValue<string>()); }}注意事項
The generator is lazy, so an abandoned loop costs only the pages you consumed.
ほかの提供先
Contacts.SaveAsync
Save an address as a contact, or keep one that was recorded
Task<JsonObject> SaveAsync( string email, IReadOnlyDictionary<string, object?>? body = null, string? apiKey = null, CancellationToken cancellationToken = default)Does what Add to contacts and Keep in contacts do in the app, and is safe to call whatever state the address is in. An address that is not a contact yet becomes one with source manual. A contact recorded from a send becomes manual. A contact already saved keeps what it has. A deleted address is brought back.
name in the body replaces the stored name and leaving it out keeps it. notes replaces the stored notes and null clears them. Unlike Contacts.CreateAsync, an address already in the book is not an error, and unlike Contacts.UpdateAsync, an address not in the book is not one either.
パラメーター
emailstring必須The address, trimmed and lower cased on the server.
namestringUp to 200 characters. Left out, the stored name is kept.
notesstringUp to 5,000 characters. Null clears the notes, and left out, they are kept.
apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject for the contact as it stands after the save, with audiences.
例
var contact = await client.Contacts.SaveAsync("[email protected]", body: new Body { ["name"] = "Grace Hopper" }); Console.WriteLine(contact.ToJsonString());注意事項
The server answers 201 for a new contact and 200 for one that was there. The SDK returns the same object for both, so compare
createdAtwithupdatedAtif you need to tell them apart.Safe to replay, so the SDK retries it after a network failure.
A new contact joins the default audience, as it does from
Contacts.CreateAsync.
ほかの提供先
- API
PUT /contacts/{email}- TypeScript
contacts.save()- Python
contacts.save()- Ruby
contacts.save- PHP
contacts->save- Go
Contacts.Save- Java
contacts().save- CLI
openemail contacts save
Contacts.DeleteManyAsync
Delete up to 200 contacts in one call
Task<JsonObject> DeleteManyAsync( IEnumerable<string> emails, string? apiKey = null, CancellationToken cancellationToken = default)Deletes every address in emails the way Contacts.DeleteAsync deletes one: a saved contact goes with its notes, its photo and every audience membership, and every address is hidden, so mail sent to it from the app composer does not record it again. Addresses that were only seen in mail are hidden too.
An entry that is not an address comes back in invalid and the rest still go through. A repeated address counts once. There is no undo.
パラメーター
emailsIEnumerable<string>必須1 to 200 addresses, matched case insensitively. More than 200, or none, is a 422 on
emails.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject with object set to contact_batch_delete, deleted, saved and invalid. deleted counts the addresses deleted and hidden, saved how many of them were saved contacts.
例
var result = await client.Contacts.DeleteManyAsync(new[] { "[email protected]", "[email protected]", "not an address" }); Console.WriteLine($"{result["deleted"]} deleted, {result["saved"]} of them saved contacts"); if ((result["invalid"]?.AsArray().Count ?? 0) > 0){ Console.WriteLine($"Skipped: {string.Join(", ", result["invalid"]?.AsArray() ?? [])}");}注意事項
Safe to replay: deleting an address twice leaves it deleted and hidden, so the SDK retries it after a network failure.
No mail is deleted, and nobody is unsubscribed from anything.
ほかの提供先
Contacts.SetPhotoAsync
Upload the photo shown for a contact
Task<JsonObject> SetPhotoAsync( string email, Stream data, string? contentType = null, string? apiKey = null, CancellationToken cancellationToken = default)Sends the image bytes as the request body, replacing any photo the contact had. PNG, JPEG, WebP and GIF are accepted, up to 5 MB. The server fits the image into a 512 pixel square, stores it as WebP, keeps the first frame of an animation, and answers with the contact and its new photoUrl.
data is a readable Stream. The type is read from contentType:. Without it the bytes go as application/octet-stream and the server refuses them with 422 invalid_image.
The address has to be a saved contact already: Contacts.SaveAsync it first.
パラメーター
emailstring必須The contact's address, matched case insensitively.
dataStream必須The image: a readable
Stream.contentTypestring?image/png,image/jpeg,image/webporimage/gif. Required, because aStreamcarries no type of its own.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject for the contact with the new photoUrl.
例
await client.Contacts.SaveAsync("[email protected]"); await using var photo = File.OpenRead("photo.jpg"); var contact = await client.Contacts.SetPhotoAsync("[email protected]", photo, contentType: "image/jpeg"); Console.WriteLine($"Photo at {contact["photoUrl"]}");注意事項
An address that is not a saved contact is a 404
contact_not_found.A busy image service answers 503
image_busy, which the SDK retries like any other 503.Every upload gets a new URL, so a cached old photo never shows under the new one.
ほかの提供先
Contacts.RemovePhotoAsync
Remove a contact photo
Task<JsonObject> RemovePhotoAsync( string email, string? apiKey = null, CancellationToken cancellationToken = default)Takes the photo off the contact and deletes the stored image, the way Remove does on a contact in the app. The contact answers with photoUrl null. Removing a photo from a contact that has none changes nothing.
パラメーター
emailstring必須The contact's address, matched case insensitively.
apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject for the contact with photoUrl null.
例
var contact = await client.Contacts.RemovePhotoAsync("[email protected]"); Console.WriteLine($"{contact["email"]} now shows {contact["photoUrl"]?.ToString() ?? "initials"}");注意事項
An address that is not a saved contact is a 404
contact_not_found.Safe to replay, so the SDK retries it after a network failure.
ほかの提供先
Contacts.BlockAsync
Block an address
Task<JsonObject> BlockAsync( string email, string? apiKey = null, CancellationToken cancellationToken = default)Puts the address on the workspace blocklist, the same list Settings.UpdateAsync edits as blockedSenders, so mail from it is refused from then on. This is Block on a contact in the app. A plus tag is dropped: blocking [email protected] blocks [email protected], and every tag of it.
When a rule already blocks the address, a whole-domain rule included, nothing is added: created is false and blockedBy names that rule. The address does not have to be a contact.
パラメーター
emailstring必須The address to block.
apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject with object set to contact_block, email, blocked set to true, blockedBy and created.
例
var block = await client.Contacts.BlockAsync("[email protected]"); if ((bool?)block["created"] == true){ Console.WriteLine($"Blocked {block["email"]}");}else{ Console.WriteLine($"Already blocked by {block["blockedBy"]?["rule"]} in {block["blockedBy"]?["list"]}");}注意事項
It needs
settings:writerather thancontacts:write, because it writes the blocklist rather than the contact.Safe to replay, so the SDK retries it after a network failure.
An address with fewer than two letters or numbers is refused with 422
blocklist_entry_too_broad.A key limited to particular addresses or domains gets 422
capability_unsupportedonaddressAllowlist, because the blocklist belongs to the whole workspace and filters the mail of every address in it.
ほかの提供先
Contacts.UnblockAsync
Unblock an address
Task<JsonObject> UnblockAsync( string email, string? apiKey = null, CancellationToken cancellationToken = default)Takes every workspace blocklist rule that blocks the address off the list and lists them in removed. This is Unblock on a contact in the app.
When one of them is a whole-domain rule, in blockedDomains, everybody at that domain is unblocked with it, so check removed when that matters. Rules set for one address or one domain in the settings are not touched. An address that no rule blocks answers with removed empty.
パラメーター
emailstring必須The address to unblock.
apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject with object set to contact_block, email, blocked set to false and removed, each entry of which is an object with rule and ListAsync.
例
using OpenEmail.Constants; var unblock = await client.Contacts.UnblockAsync("[email protected]"); foreach (var removed in unblock["removed"]?.AsArray() ?? []){ if ((string?)removed?["list"] == ContactBlockLists.BlockedDomains) { Console.WriteLine($"Everybody at {removed?["rule"]} is unblocked too"); }}注意事項
Safe to replay, so the SDK retries it after a network failure.
A key limited to particular addresses or domains gets 422
capability_unsupportedonaddressAllowlist, because the blocklist belongs to the whole workspace and filters the mail of every address in it.
ほかの提供先
Contacts.ListThreadsAsync
List the conversations with one person
Task<Page> ListThreadsAsync( string email, string? q = null, string? sort = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns one page of the threads the address wrote or was written to, in every folder: the Mail tab on a contact in the app. Each row is a summary, subject, from, receivedAt, messageCount, hasUnread and labels, and Threads.GetAsync reads the messages behind its id.
limit: takes 1 to 100 and defaults to 25. Pass nextCursor back as cursor:, with the same q: and sort:, while hasMore is true.
パラメーター
emailstring必須The address. It does not have to be a saved contact.
qstring?Searches inside those threads, with the mailbox search syntax, up to 200 characters.
sortstring?newest(the default),oldest,senderorsubject, also inOpenEmail\Constants\ContactThreadSorts.limitint?Threads per page, 1 to 100. The server defaults to 25.
cursorstring?The
nextCursorfrom the previous page. Never build one yourself.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A Page of thread summary objects, with items, hasMore and nextCursor.
例
var threads = await client.Contacts.ListThreadsAsync("[email protected]", q: "invoice", limit: 10); foreach (var thread in threads){ Console.WriteLine($"{thread["receivedAt"]} {thread["subject"]} ({thread["messageCount"]}){((bool?)thread["hasUnread"] == true ? ", unread" : "")}");}注意事項
It needs
threads:read, because it reads mail rather than the contact.A key limited to particular addresses or domains gets 422
capability_unsupportedonaddressAllowlist, because a contact's threads and activity are read from the mail of every address in the workspace.
ほかの提供先
Contacts.ListAllThreadsAsync
Collect every conversation with one person into one object
Task<IReadOnlyList<JsonObject>> ListAllThreadsAsync( string email, string? q = null, string? sort = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Follows nextCursor from page to page and returns every thread Contacts.ListThreadsAsync would list for the address, in the same order.
Everything is held in memory before the call returns. Prefer Contacts.IterateThreadsAsync when you can stop early.
パラメーター
emailstring必須The address. It does not have to be a saved contact.
qstring?Searches inside those threads, with the mailbox search syntax, up to 200 characters.
sortstring?newest(the default),oldest,senderorsubject.limitint?Page size per request, from 1 to 100, defaulting to 25 on the server.
cursorstring?A cursor from an earlier page to start after.
apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request.
戻り値
A list of thread summary objects holding every thread across all pages.
例
var threads = await client.Contacts.ListAllThreadsAsync("[email protected]", sort: "oldest", limit: 100); Console.WriteLine(threads.Count);注意事項
A failure on any page throws out of the whole call, and the threads already fetched are discarded.
ほかの提供先
Contacts.IterateThreadsAsync
Stream the conversations with one person one thread at a time
IAsyncEnumerable<JsonObject> IterateThreadsAsync( string email, string? q = null, string? sort = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns an IAsyncEnumerable<JsonObject> that yields the threads Contacts.ListThreadsAsync lists for the address, one at a time, 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.
パラメーター
emailstring必須The address. It does not have to be a saved contact.
qstring?Searches inside those threads, with the mailbox search syntax, up to 200 characters.
sortstring?newest(the default),oldest,senderorsubject.limitint?Page size per request, from 1 to 100, defaulting to 25 on the server.
cursorstring?A cursor from an earlier page to start after.
apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request.
戻り値
An IAsyncEnumerable<JsonObject> that yields one thread summary per step.
例
await foreach (var thread in client.Contacts.IterateThreadsAsync("[email protected]")){ if ((bool?)thread["hasUnread"] == true) { Console.WriteLine($"Newest unread: {thread["subject"]} from {thread["from"]?["email"]}"); break; }}注意事項
The generator is lazy, so an abandoned loop costs only the pages you consumed.
ほかの提供先
Contacts.ActivityAsync
Read how mail with one person has gone over a window
Task<JsonObject> ActivityAsync( string email, int? minutes = null, string? grain = null, int? offsetMinutes = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns the numbers behind the Activity tab on a contact in the app, over a window that ends now: messages received from the address and sent to it per bucket, the threads that moved, the threads whose newest message is theirs and so waits on a reply from the mailbox, when each side last wrote, and the median time each side takes to answer, in milliseconds.
minutes: sets how far back the window reaches, 90 days by default. grain: sets the bucket width and the key shape, YYYY-MM-DD, YYYY-MM-DDTHH or YYYY-MM-DDTHH:MM, and offsetMinutes: shifts the boundaries so days break where the reader's day does. buckets is sparse and oldest first. Mail in the bin or in spam is left out.
パラメーター
emailstring必須The address. It does not have to be a saved contact.
minutesint?Window length in minutes, from 1 to about 20 years. The server defaults to 90 days.
grainstring?Bucket width:
minute,hourorday, defaulting today.offsetMinutesint?Minutes east of UTC to cut the buckets in, from -840 to 840, defaulting to 0. Pass
(int)TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now).TotalMinutesfor the local zone.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject with object set to contact_activity, email, since, until, grain, buckets, totals and replyTime. totals has received, sent, threads, waiting, lastReceivedAt and lastSentAt, and replyTime has yours and theirs, each null when there is no reply to measure.
例
var activity = await client.Contacts.ActivityAsync( "[email protected]", minutes: 30 * 24 * 60, offsetMinutes: (int)TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now).TotalMinutes);var totals = activity["totals"]; Console.WriteLine($"{totals?["received"]} received, {totals?["sent"]} sent, {totals?["waiting"]} waiting on a reply"); if ((double?)activity["replyTime"]?["yours"] is { } milliseconds){ Console.WriteLine($"You answer in {Math.Round(milliseconds / 3600000, 1)} hours");}注意事項
It needs
threads:read, because it reads mail rather than the contact.Read only, so the SDK retries it after a network failure like any other read.
A key limited to particular addresses or domains gets 422
capability_unsupportedonaddressAllowlist, because a contact's threads and activity are read from the mail of every address in the workspace.
ほかの提供先
Contacts.ListEventsAsync
List the events recorded for one contact
Task<Page> ListEventsAsync( string email, string? name = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns one page of the events Events.SendAsync recorded for a contact in the last 90 days, the most recent first by when they happened. Each has its name, properties, occurredAt and mode, which is test for an event a test key sent.
limit: takes 1 to 200 and defaults to 50. Pass nextCursor back as cursor:, with the same name:, while hasMore is true. ListAllEventsAsync and IterateEventsAsync do that walk for you.
パラメーター
emailstring必須The contact, by email address, compared without case. The
contactIdan event or an enrollment carries works here too.namestring?Only events with exactly this name.
limitint?Events per page, a whole number from 1 to 200. The server defaults to 50.
cursorstring?The
nextCursorfrom the previous page, passed back exactly as it came. One that names no event of this contact is a 400invalid_cursor.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A Page with items, hasMore and nextCursor. Each item has id, contactId, email, name, properties, occurredAt, mode and createdAt.
例
var page = await client.Contacts.ListEventsAsync("[email protected]", name: "order.placed"); foreach (var entry in page){ Console.WriteLine($"{entry["occurredAt"]} {entry["name"]} {entry["properties"]}");}注意事項
An address or id nobody you can reach has is 404
contact_not_found. An app a member connected reads only the contacts that member added.Read only, so the SDK retries it after a network failure like any other read.
ほかの提供先
Contacts.ListAllEventsAsync
Collect every event of one contact into one list
Task<IReadOnlyList<JsonObject>> ListAllEventsAsync( string email, string? name = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Follows nextCursor from page to page and returns every event recorded for the contact in the last 90 days, the most recent first, in the shape ListEventsAsync returns. limit sets the page size of each request, not the total.
パラメーター
emailstring必須The contact, by email address, compared without case. The
contactIdan event or an enrollment carries works here too.namestring?Only events with exactly this name.
limitint?Page size per request, from 1 to 200, defaulting to 50 on the server.
cursorstring?A
nextCursorfrom an earlier page to start after.apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request in flight and ends the whole walk.
戻り値
A list of JsonObject items holding every matching event across all pages, each shaped like an item of ListEventsAsync.
例
var events = await client.Contacts.ListAllEventsAsync("[email protected]");var names = events.Select(entry => (string?)entry["name"]).Distinct(); Console.WriteLine($"{events.Count} events: {string.Join(", ", names)}");注意事項
A failure on any page throws out of the whole call.
ほかの提供先
Contacts.IterateEventsAsync
Stream the events of one contact one at a time
IAsyncEnumerable<JsonObject> IterateEventsAsync( string email, string? name = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns an IAsyncEnumerable<JsonObject> that yields the events of a contact one by one, the most recent first, and requests the next page only once the current one is drained. Breaking out of the loop stops the requests.
パラメーター
emailstring必須The contact, by email address, compared without case. The
contactIdan event or an enrollment carries works here too.namestring?Only events with exactly this name.
limitint?Page size per request, from 1 to 200, defaulting to 50 on the server.
cursorstring?A
nextCursorfrom an earlier page to start after.apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request in flight and ends the whole walk.
戻り値
An IAsyncEnumerable<JsonObject> that yields one event per step.
例
await foreach (var entry in client.Contacts.IterateEventsAsync("[email protected]")){ if ((string?)entry["name"] == "plan.cancelled") { Console.WriteLine($"Cancelled on {entry["occurredAt"]}"); break; }}注意事項
The enumerable is lazy, so an abandoned loop costs only the pages you consumed.
ほかの提供先
Contacts.ListCardsAsync
List the address book as contact cards
Task<Page> ListCardsAsync( string? email = null, bool? withoutEmail = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns one page of contact cards, newest first. A card is a saved contact with everything an address book keeps for it: phone numbers, other email addresses, postal addresses, websites, organisation, department, job title, birthday, nickname and the name in parts. Cards with no email address, such as a plumber saved on a phone, are listed too. It is the address book phones and computers sync over CardDAV.
email: finds the card of one saved contact, and withoutEmail: true lists only the cards with no address. An address that was only ever mailed, and never saved, has no card.
Paging is keyset. limit: takes 1 to 200 and defaults to 50, and nextCursor goes back as cursor: while hasMore is true. Never build a cursor yourself.
パラメーター
emailstring?Only the card of the saved contact with this address.
withoutEmailbool?True lists only the cards that have no email address.
limitint?Cards per page, a whole number from 1 to 200. The server defaults to 50.
cursorstring?The
nextCursorfrom the previous page. Never build one yourself.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A Page of card objects, with items, hasMore and nextCursor. Each card has id, uid, email, name, nameParts, nickname, organization, department, title, birthday, notes, the lists emails, phones, addresses and urls, photoUrl, createdAt and updatedAt.
例
var page = await client.Contacts.ListCardsAsync(withoutEmail: true); foreach (var card in page){ Console.WriteLine($"{card["name"]?.ToString() ?? "No name"}: {string.Join(", ", (card["phones"]?.AsArray() ?? []).Select(row => row?["value"]))}");} if (page.HasMore){ var next = await client.Contacts.ListCardsAsync(withoutEmail: true, cursor: page.NextCursor); Console.WriteLine($"{next.Count} more");}注意事項
Every member reads the same address book through a key, since a key acts for the workspace owner.
A cursor that names no card is a 400
invalid_cursor. Start again without one.
ほかの提供先
Contacts.ListAllCardsAsync
Collect every contact card into one object
Task<IReadOnlyList<JsonObject>> ListAllCardsAsync( string? email = null, bool? withoutEmail = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Follows nextCursor from page to page and returns every card in the address book, newest first. It takes the same email: and withoutEmail: filters as Contacts.ListCardsAsync.
Everything is held in memory before the call returns. Prefer Contacts.IterateCardsAsync when you can stop early. limit: sets the page size of each request, not the total.
パラメーター
emailstring?Only the card of the saved contact with this address.
withoutEmailbool?True lists only the cards that have no email address.
limitint?Page size per request, from 1 to 200, defaulting to 50 on the server.
cursorstring?A cursor from an earlier page to start after.
apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request.
戻り値
A list of card objects holding every card across all pages.
例
var cards = await client.Contacts.ListAllCardsAsync(); Console.WriteLine($"{cards.Count} cards in the address book");注意事項
A failure on any page throws out of the whole call, and the cards already fetched are discarded.
ほかの提供先
Contacts.IterateCardsAsync
Stream the address book one card at a time
IAsyncEnumerable<JsonObject> IterateCardsAsync( string? email = null, bool? withoutEmail = null, int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns an IAsyncEnumerable<JsonObject> that yields cards one at a time, newest 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. It takes the same email: and withoutEmail: filters as Contacts.ListCardsAsync.
パラメーター
emailstring?Only the card of the saved contact with this address.
withoutEmailbool?True lists only the cards that have no email address.
limitint?Page size per request, from 1 to 200, defaulting to 50 on the server.
cursorstring?A cursor from an earlier page to start after.
apiKeystring?Overrides the client's API key for every page of this walk.
cancellationTokenCancellationTokenCancels the request.
戻り値
An IAsyncEnumerable<JsonObject> that yields one card per step.
例
await foreach (var card in client.Contacts.IterateCardsAsync()){ if (card["birthday"] is not null) { Console.WriteLine($"{card["name"]}: {card["birthday"]}"); }}注意事項
The generator is lazy, so an abandoned loop costs only the pages you consumed.
ほかの提供先
Contacts.GetCardAsync
Get one contact card
Task<JsonObject> GetCardAsync( string id, string? apiKey = null, CancellationToken cancellationToken = default)Returns one card with everything it holds. To find the card of a saved contact by its address, pass email: to Contacts.ListCardsAsync.
パラメーター
idstring必須The card id,
ccd_followed by 24 characters, fromContacts.ListCardsAsyncorContacts.GetCardAsync.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject with id, uid, the vCard UID that phones and computers know the card by, email, null on a card with no address, name, nameParts, nickname, organization, department, title, birthday, notes, photoUrl, createdAt and updatedAt. emails, phones and urls are lists of objects with value, label and customLabel, and addresses is a list of objects with label, customLabel, street, locality, region, postalCode and country.
例
try{ var card = await client.Contacts.GetCardAsync("ccd_0123456789abcdef01234567"); Console.WriteLine($"{card["name"]}, {card["organization"]?.ToString() ?? "no organisation"}");}catch (OpenEmailApiException error) when (error.IsNotFound){ Console.WriteLine("No card has that id");}注意事項
An id that names no card is a 404
contact_card_not_found, thrown as anOpenEmailApiExceptionwhoseIsNotFoundis true.
ほかの提供先
Contacts.CreateCardAsync
Add a card to the address book
Task<JsonObject> CreateCardAsync( IReadOnlyDictionary<string, object?> body, string? apiKey = null, CancellationToken cancellationToken = default)Adds a contact card. With email the card is a saved contact as well, the same one Contacts.CreateAsync makes, and an address the workspace already knows from mail becomes saved. Without one it is a card on its own, kept for its name, phone numbers and the rest. A card needs at least a name, an email address, a phone number or an organisation.
Each entry in emails, phones and urls is an object with value, and optionally label, one of OpenEmail\Constants\ContactCardLabels, and customLabel, a label of your own.
Phones and computers that sync the address book over CardDAV get the new card on their next sync.
パラメーター
emailstringThe address OpenEmail knows the contact by. With it the card is a saved contact as well. A saved contact keeps its address, so put any other address in
emails.namestringThe full name the address book shows, up to 200 characters.
namePartsdictionaryThe name in parts, a dictionary with
prefix,given,middle,familyandsuffix, the way phones keep it.nicknamestringA nickname.
organizationstringThe company or organisation.
departmentstringThe department within the organisation.
titlestringThe job title.
birthdaystringYYYY-MM-DD, or--MM-DDwhen the year is not known.notesstringFree-form notes. On a saved contact these are the notes the contact page shows.
emailslistOther email addresses besides
email, each a dictionary withvalue, and optionallylabelandcustomLabel.phoneslistPhone numbers, each a dictionary with
value, and optionallylabelandcustomLabel.addresseslistPostal addresses, each a dictionary with any of
label,customLabel,street,locality,region,postalCodeandcountry.urlslistWebsites and profile links, each a dictionary with
value, and optionallylabelandcustomLabel.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject for the new card, with the fields Contacts.GetCardAsync returns.
例
using OpenEmail.Constants; var card = await client.Contacts.CreateCardAsync(new Body{ ["email"] = "[email protected]", ["name"] = "Ada Lovelace", ["organization"] = "Analytical Engines", ["phones"] = new[] { new Body { ["value"] = "+44 20 7946 0000", ["label"] = ContactCardLabels.Work }, }, ["birthday"] = "1815-12-10",}); Console.WriteLine($"{card["id"]} {card["email"]}");注意事項
The SDK does not retry it after a network failure, because a second call would make a second card.
An address that already belongs to another card is a 409
contact_card_email_taken, and a card with nothing to keep a 422invalid_contact_card.A workspace that already keeps as many cards as it may gets a 409
contact_card_limit. Delete some before you add more.
ほかの提供先
Contacts.UpdateCardAsync
Change a contact card
Task<JsonObject> UpdateCardAsync( string id, IReadOnlyDictionary<string, object?> patch, string? apiKey = null, CancellationToken cancellationToken = default)Changes the fields you send and leaves the rest alone. Null clears a field, and a list you send (emails, phones, addresses or urls) replaces the whole list, so read the card first when you mean to add one entry.
On a saved contact, name and notes are the contact's own, so the contact page shows the change. email can only be given to a card that has none, which makes it a saved contact. A saved contact keeps its address: add another address to emails instead.
Phones and computers that sync the address book over CardDAV get the change on their next sync.
パラメーター
idstring必須The card id,
ccd_followed by 24 characters, fromContacts.ListCardsAsyncorContacts.GetCardAsync.emailstringThe address OpenEmail knows the contact by. Given to a card that has none, it makes the card a saved contact. A saved contact keeps its address, so put any other address in
emails.namestringThe full name the address book shows, up to 200 characters.
namePartsdictionaryThe name in parts, a dictionary with
prefix,given,middle,familyandsuffix, the way phones keep it.nicknamestringA nickname.
organizationstringThe company or organisation.
departmentstringThe department within the organisation.
titlestringThe job title.
birthdaystringYYYY-MM-DD, or--MM-DDwhen the year is not known.notesstringFree-form notes. On a saved contact these are the notes the contact page shows.
emailslistOther email addresses besides
email, each a dictionary withvalue, and optionallylabelandcustomLabel. The list replaces the one the card has.phoneslistPhone numbers, each a dictionary with
value, and optionallylabelandcustomLabel. The list replaces the one the card has.addresseslistPostal addresses, each a dictionary with any of
label,customLabel,street,locality,region,postalCodeandcountry. The list replaces the one the card has.urlslistWebsites and profile links, each a dictionary with
value, and optionallylabelandcustomLabel. The list replaces the one the card has.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject for the card as it stands after the change.
例
using OpenEmail.Constants; var card = await client.Contacts.GetCardAsync("ccd_0123456789abcdef01234567");var phones = new List<object?>(card["phones"]?.AsArray() ?? []){ new Body { ["value"] = "+1 555 0100", ["label"] = ContactCardLabels.Mobile },}; var updated = await client.Contacts.UpdateCardAsync(card["id"]!.GetValue<string>(), new Body { ["phones"] = phones }); Console.WriteLine($"{updated["phones"]?.AsArray().Count} phone numbers");注意事項
The SDK retries this call after a network failure, since the same patch sent twice leaves the same card.
Changing the address of a saved contact is a 422
invalid_contact_card, and an address that already belongs to another card a 409contact_card_email_taken.An id that names no card is a 404
contact_card_not_found.
ほかの提供先
Contacts.DeleteCardAsync
Delete a contact card
Task<JsonObject> DeleteCardAsync( string id, string? apiKey = null, CancellationToken cancellationToken = default)Removes the card from the address book and from every phone and computer that syncs it. On a saved contact it is the same as Contacts.DeleteAsync: the contact goes with its notes, photo and audiences, and the address is hidden from the people list and the suggestions.
パラメーター
idstring必須The card id,
ccd_followed by 24 characters, fromContacts.ListCardsAsyncorContacts.GetCardAsync.apiKeystring?Overrides the client's API key for this call only.
cancellationTokenCancellationTokenCancels the request.
戻り値
A JsonObject with object set to contact_card, id and deleted set to true.
例
var removed = await client.Contacts.DeleteCardAsync("ccd_0123456789abcdef01234567"); Console.WriteLine($"{removed["id"]} deleted");注意事項
There is no undo, and the SDK does not retry it after a network failure.
An id that names no card is a 404
contact_card_not_found.
ほかの提供先
Contacts.ImportVcfAsync
Import a contacts file
Task<JsonObject> ImportVcfAsync( Stream data, string? filename = null, string? apiKey = null, CancellationToken cancellationToken = default)Sends a vCard (.vcf) file as the request body and queues it. Every card in it becomes a contact card, with its phone numbers, addresses and the rest. Poll GetImportAsync until status is completed.
The file may be 20 MB. Imported contacts join no audience, so a broadcast never reaches them because of an import. A card whose address or UID is already in the address book is counted under merged and left as it is, and a card with no address is matched on its phone number. A workspace keeps 20,000 cards, and the cards past that are counted under skipped.
data is a readable Stream, and it goes out as text/vcard.
パラメーター
dataStream必須The .vcf file: a readable
Stream.filenamestring?The name to show for the file in the list of imports, at most 255 characters.
cancellationTokenCancellationTokenCancels the request.
apiKeystring?Overrides the client's API key for this call only.
戻り値
A JsonObject with status: queued.
例
await using var file = File.OpenRead("contacts.vcf"); var import = await client.Contacts.ImportVcfAsync(file, filename: "contacts.vcf"); Console.WriteLine($"{import["id"]} is {import["status"]}");注意事項
A body that holds no vCard is a 400
not_a_contacts_file, and an empty one a 400item_import_empty.A file over 20 MB is a 413
item_import_too_large.To send text you already hold, encode it first with
new TextEncoder().encode(text).An upload that outlasts the client
Timeoutfails as a network error, so raise it on the client for a large file on a slow connection.Not retried automatically.
ほかの提供先
Contacts.ListImportsAsync
List contacts imports
Task<Page> ListImportsAsync( int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns one page of the contacts files and address books brought in, newest first, each with what it added and what it left out. Beside the files sent with ImportVcfAsync it lists the address books that came with a mailbox import, and those carry the id of that import in parentImportId.
Paging is keyset. limit: takes 1 to 100 and defaults to 25, and nextCursor goes back as cursor: while hasMore is true. ListAllImportsAsync and IterateImportsAsync do that walk for you.
パラメーター
limitint?Imports per page, a whole number from 1 to 100. The server defaults to 25.
cursorstring?The
nextCursorfrom the previous page. Never build one yourself.cancellationTokenCancellationTokenCancels the request.
apiKeystring?Overrides the client's API key for this call only.
戻り値
A Page with items, hasMore and nextCursor.
例
var page = await client.Contacts.ListImportsAsync(limit: 10); foreach (var import in page){ Console.WriteLine($"{import["id"]} {import["source"]} {import["status"]}: {import["counts"]?["imported"]} cards added");}注意事項
sourceisfilefor an upload.takeout,carddavandmicrosoftcame with a mailbox import.A cursor that names no import is a 400
invalid_cursor.A GET is retried automatically on network failure and on 408, 500, 502, 503 and 504 responses, up to the client
MaxRetries, and on a 429 only when it carries aRetry-Afterof a minute or less.
ほかの提供先
Contacts.ListAllImportsAsync
Collect every contacts import into one list
Task<IReadOnlyList<JsonObject>> ListAllImportsAsync( int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Follows nextCursor from page to page and returns every contacts import, newest first.
Everything is held in memory before the call returns. Prefer IterateImportsAsync when you can stop early. limit sets the page size of each request, not the total.
パラメーター
limitint?Page size per request, from 1 to 100, defaulting to 25 on the server.
cursorstring?A cursor from an earlier page to start after.
cancellationTokenCancellationTokenCancels the request in flight and rejects the whole walk.
apiKeystring?Overrides the client's API key for every page of this walk.
戻り値
A list of JsonObject items holding every import across all pages.
例
var imports = await client.Contacts.ListAllImportsAsync(); Console.WriteLine($"{imports.Count} contacts imports, {imports.Count(import => (bool?)import["undoable"] == true)} of them can be undone");注意事項
A failure on any page rejects the whole call, and the imports already fetched are discarded.
ほかの提供先
Contacts.IterateImportsAsync
Stream contacts imports one at a time
IAsyncEnumerable<JsonObject> IterateImportsAsync( int? limit = null, string? cursor = null, string? apiKey = null, CancellationToken cancellationToken = default)Returns an IAsyncEnumerable<JsonObject> that yields contacts imports one by one, newest first, and requests the next page only once the current one is drained. Nothing is fetched until you consume it, and breaking out of the loop stops the requests.
パラメーター
limitint?Page size per request, from 1 to 100, defaulting to 25 on the server.
cursorstring?A cursor from an earlier page to start after.
cancellationTokenCancellationTokenCancels the request in flight and rejects the whole walk.
apiKeystring?Overrides the client's API key for every page of this walk.
戻り値
An IAsyncEnumerable<JsonObject> yielding one import per step.
例
await foreach (var import in client.Contacts.IterateImportsAsync(limit: 50)){ if ((string?)import["status"] == "failed") { Console.WriteLine($"{import["id"]} failed"); break; }}注意事項
The generator is lazy, so an abandoned loop costs only the pages you consumed.
ほかの提供先
Contacts.GetImportAsync
Get a contacts import
Task<JsonObject> GetImportAsync( string id, string? apiKey = null, CancellationToken cancellationToken = default)Returns one contacts import with its counts and its report: the files it read, how many cards it left out and why, and up to 20 of the cards it left out. Poll it after ImportVcfAsync until status is completed or failed.
counts.imported is what was added, counts.merged the cards left as they were because they were already in the address book, and counts.skipped what was left out, which report.skipped breaks down by reason: limit for a card past the 20,000 a workspace keeps, invalid for one that could not be read and empty for one that held nothing.
パラメーター
idstring必須Contacts import id,
iimp_followed by 24 hex characters.cancellationTokenCancellationTokenCancels the request.
apiKeystring?Overrides the client's API key for this call only.
戻り値
A JsonObject with status, counts, report, undoable and when it started, finished and was undone.
例
var import = await client.Contacts.GetImportAsync("iimp_3f9a1c07d2b84e6a9c5b1f20"); Console.WriteLine($"{import["status"]}: {import["counts"]?["imported"]} added, {import["counts"]?["skipped"]} left out");注意事項
An id that names no contacts import is a 404
item_import_not_found.A GET is retried automatically on network failure and on 408, 500, 502, 503 and 504 responses, up to the client
MaxRetries, and on a 429 only when it carries aRetry-Afterof a minute or less.
ほかの提供先
Contacts.UndoImportAsync
Remove what a contacts import added
Task<JsonObject> UndoImportAsync( string id, string? apiKey = null, CancellationToken cancellationToken = default)Deletes every contact and card the import added, changed since or not, and marks the import undone. Contacts that were already in the address book are not touched.
パラメーター
idstring必須Contacts import id,
iimp_followed by 24 hex characters.cancellationTokenCancellationTokenCancels the request.
apiKeystring?Overrides the client's API key for this call only.
戻り値
A JsonObject with status: undone and undoneAt set.
例
try{ var undone = await client.Contacts.UndoImportAsync("iimp_3f9a1c07d2b84e6a9c5b1f20"); Console.WriteLine($"{undone["id"]} is {undone["status"]} since {undone["undoneAt"]}");}catch (OpenEmailApiException error) when (error.IsConflict){ Console.WriteLine("That import is still running or was already removed");}注意事項
An import that is still running, or was already removed, is a 409
item_import_not_undoable.undoableon the import says whether the call would remove anything.An id that names no contacts import is a 404
item_import_not_found.Not retried automatically.