Files
opencloud/pkg/jmap/jmap_model.go
Pascal Bleser 5dc1f28e87 groupware: improve email submission and testing
* jmap/EmailCreate: add more attributes that were omitted: Headers,
   InReplyTo, References, Sender

 * add jmap GetEmailSubmissionStatus

 * improve email integration tests by adding a thorough test for email
   submission

 * jmap integration tests: provision principals and domains using the
   Stalwart Management API, switching from an in-memory to an internal
   directory
2025-12-09 09:15:39 +01:00

6046 lines
251 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package jmap
import (
"io"
"time"
"github.com/opencloud-eu/opencloud/pkg/jscalendar"
"github.com/opencloud-eu/opencloud/pkg/jscontact"
)
// https://www.iana.org/assignments/jmap/jmap.xml#jmap-data-types
type ObjectType string
// Where `UTCDate` is given as a type, it means a `Date` where the "time-offset"
// component MUST be `"Z"` (i.e., it must be in UTC time).
//
// For example, `"2014-10-30T06:12:00Z"`.
type UTCDate string
// Where `LocalDate` is given as a type, it means a string in the same format as `Date`
// (see [RFC8620, Section 1.4]), but with the time-offset omitted from the end.
//
// For example, `2014-10-30T14:12:00`.
//
// The interpretation in absolute time depends upon the time zone for the event, which
// may not be a fixed offset (for example when daylight saving time occurs).
//
// [RFC8620, Section 1.4]: https://www.rfc-editor.org/rfc/rfc8620.html#section-1.4
type LocalDate string
// Should the calendars events be used as part of availability calculation?
//
// This MUST be one of:
// !- `all“: all events are considered.
// !- `attending“: events the user is a confirmed or tentative participant of are considered.
// !- `none“: all events are ignored (but may be considered if also in another calendar).
//
// This should default to “all” for the calendars in the users own account, and “none” for calendars shared with the user.
type IncludeInAvailability string
type TypeOfCalendarAlert string
// `CalendarEventNotification` type.
//
// This MUST be one of
// !- `created`
// !- `updated`
// !- `destroyed`
type CalendarEventNotificationTypeOption string
// `Principal` type.
//
// This MUST be one of the following values:
// !- `individual`: This represents a single person.
// !- `group`: This represents a group of people.
// !- `resource`: This represents some resource, e.g. a projector.
// !- `location`: This represents a location.
// !- `other`: This represents some other undefined principal.
type PrincipalTypeOption string
// Algorithms in this list MUST be present in the ["HTTP Digest Algorithm Values" registry]
// defined by [RFC3230]; however, in JMAP, they must be lowercased, e.g., "md5" rather than
// "MD5".
//
// Clients SHOULD prefer algorithms listed earlier in this list.
//
// ["HTTP Digest Algorithm Values" registry]: https://www.iana.org/assignments/http-dig-alg/http-dig-alg.xhtml
type HttpDigestAlgorithm string
// The ResourceType data type is used to act as a unit of measure for the quota usage.
type ResourceType string
// The Scope data type is used to represent the entities the quota applies to.
type Scope string
// Determines which action must be performed by the MUA or MTA upon receiption.
//
// !- `manual-action`: the disposition described by the disposition type was a result of an
// explicit instruction by the user rather than some sort of automatically performed action.
// (This might include the case when the user has manually configured her MUA to automatically
// respond to valid MDN requests.) Unless prescribed otherwise in a particular mail environment,
// in order to preserve the user's privacy, this MUST be the default for MUAs.
// !- `automatic-action`: the disposition described by the disposition type was a result of an
// automatic action rather than an explicit instruction by the user for this message. This
// is typically generated by a Mail Delivery Agent (e.g., MDN generations by Sieve reject action
// [RFC5429], Fax-over-Email [RFC3249], voice message system (see Voice Profile for Internet
// Mail (VPIM) [RFC3801]), or upon delivery to a mailing list).
type ActionMode string
type SendingMode string
type DispositionTypeOption string
type Duration string
const (
JmapCore = "urn:ietf:params:jmap:core"
JmapMail = "urn:ietf:params:jmap:mail"
JmapMDN = "urn:ietf:params:jmap:mdn" // https://datatracker.ietf.org/doc/rfc9007/
JmapSubmission = "urn:ietf:params:jmap:submission"
JmapVacationResponse = "urn:ietf:params:jmap:vacationresponse"
JmapCalendars = "urn:ietf:params:jmap:calendars"
JmapContacts = "urn:ietf:params:jmap:contacts"
JmapSieve = "urn:ietf:params:jmap:sieve"
JmapBlob = "urn:ietf:params:jmap:blob"
JmapQuota = "urn:ietf:params:jmap:quota"
JmapWebsocket = "urn:ietf:params:jmap:websocket"
JmapPrincipals = "urn:ietf:params:jmap:principals"
JmapPrincipalsOwner = "urn:ietf:params:jmap:principals:owner"
JmapTasks = "urn:ietf:params:jmap:tasks"
JmapTasksRecurrences = "urn:ietf:params:jmap:tasks:recurrences"
JmapTasksAssignees = "urn:ietf:params:jmap:tasks:assignees"
JmapTasksAlerts = "urn:ietf:params:jmap:tasks:alerts"
JmapTasksMultilingual = "urn:ietf:params:jmap:tasks:multilingual"
JmapTasksCustomTimezones = "urn:ietf:params:jmap:tasks:customtimezones"
CoreType = ObjectType("Core")
PushSubscriptionType = ObjectType("PushSubscription")
MailboxType = ObjectType("Mailbox")
ThreadType = ObjectType("Thread")
EmailType = ObjectType("Email")
EmailDeliveryType = ObjectType("EmailDelivery")
SearchSnippetType = ObjectType("SearchSnippet")
IdentityType = ObjectType("Identity")
EmailSubmissionType = ObjectType("EmailSubmission")
VacationResponseType = ObjectType("VacationResponse")
MDNType = ObjectType("MDN")
QuotaType = ObjectType("Quota")
SieveScriptType = ObjectType("SieveScript")
PrincipalType = ObjectType("PrincipalType")
ShareNotificationType = ObjectType("ShareNotification")
AddressBookType = ObjectType("AddressBook")
ContactCardType = ObjectType("ContactCard")
CalendarType = ObjectType("Calendar")
CalendarEventType = ObjectType("CalendarEvent")
CalendarEventNotificationType = ObjectType("CalendarEventNotification")
ParticipantIdentityType = ObjectType("ParticipantIdentity")
JmapKeywordPrefix = "$"
JmapKeywordSeen = "$seen"
JmapKeywordDraft = "$draft"
JmapKeywordFlagged = "$flagged"
JmapKeywordAnswered = "$answered"
JmapKeywordForwarded = "$forwarded"
JmapKeywordPhishing = "$phishing"
JmapKeywordJunk = "$junk"
JmapKeywordNotJunk = "$notjunk"
JmapKeywordMdnSent = "$mdnsent"
// https://www.iana.org/assignments/imap-mailbox-name-attributes/imap-mailbox-name-attributes.xhtml
//JmapMailboxRoleAll = "all"
//JmapMailboxRoleArchive = "archive"
JmapMailboxRoleDrafts = "drafts"
//JmapMailboxRoleFlagged = "flagged"
//JmapMailboxRoleImportant = "important"
JmapMailboxRoleInbox = "inbox"
JmapMailboxRoleJunk = "junk"
JmapMailboxRoleSent = "sent"
//JmapMailboxRoleSubscribed = "subscribed"
JmapMailboxRoleTrash = "trash"
CalendarAlertType = TypeOfCalendarAlert("CalendarAlert")
CalendarEventNotificationTypeOptionCreated = CalendarEventNotificationTypeOption("created")
CalendarEventNotificationTypeOptionUpdated = CalendarEventNotificationTypeOption("updated")
CalendarEventNotificationTypeOptionDestroyed = CalendarEventNotificationTypeOption("destroyed")
// This represents a single person.
PrincipalTypeOptionIndividual = PrincipalTypeOption("individual")
// This represents a group of people.
PrincipalTypeOptionGroup = PrincipalTypeOption("group")
// This represents some resource, e.g. a projector.
PrincipalTypeOptionResource = PrincipalTypeOption("resource")
// This represents a location.
PrincipalTypeOptionLocation = PrincipalTypeOption("location")
// This represents some other undefined principal.
PrincipalTypeOptionOther = PrincipalTypeOption("other")
HttpDigestAlgorithmAdler32 = HttpDigestAlgorithm("adler32")
HttpDigestAlgorithmCrc32c = HttpDigestAlgorithm("crc32c")
HttpDigestAlgorithmMd5 = HttpDigestAlgorithm("md5")
HttpDigestAlgorithmSha = HttpDigestAlgorithm("sha")
HttpDigestAlgorithmSha256 = HttpDigestAlgorithm("sha-256")
HttpDigestAlgorithmSha512 = HttpDigestAlgorithm("sha-512")
HttpDigestAlgorithmUnixSum = HttpDigestAlgorithm("unixsum")
HttpDigestAlgorithmUnixcksum = HttpDigestAlgorithm("unixcksum")
// The quota is measured in a number of data type objects.
//
// For example, a quota can have a limit of 50 `Mail` objects.
ResourceTypeCount = ResourceType("count")
// The quota is measured in size (in octets).
//
// For example, a quota can have a limit of 25000 octets.
ResourceTypeOctets = ResourceType("octets")
// The quota information applies to just the client's account.
ScopeAccount = Scope("account")
// The quota information applies to all accounts sharing this domain.
ScopeDomain = Scope("domain")
// The quota information applies to all accounts belonging to the server.
ScopeGlobal = Scope("global")
// The disposition described by the disposition type was a result of an explicit instruction by the
// user rather than some sort of automatically performed action.
//
// (This might include the case when the user has manually configured her MUA to automatically
// respond to valid MDN requests.)
//
// Unless prescribed otherwise in a particular mail environment, in order to preserve the user's
// privacy, this MUST be the default for MUAs.
ActionModeManualAction = ActionMode("manual-action")
// The disposition described by the disposition type was a result of an automatic action rather than
// an explicit instruction by the user for this message.
//
// This is typically generated by a Mail Delivery Agent (e.g., MDN generations by Sieve reject
// action [RFC5429], Fax-over-Email [RFC3249], voice message system (see Voice Profile
// for Internet Mail (VPIM) [RFC3801]), or upon delivery to a mailing list).
ActionModeAutomaticAction = ActionMode("automatic-action")
// The user explicitly gave permission for this particular MDN to be sent.
//
// Unless prescribed otherwise in a particular mail environment, in order to preserve the
// user's privacy, this MUST be the default for MUAs.
SendingModeMdnSentManually = SendingMode("mdn-sent-manually")
// The MDN was sent because the MUA had previously been configured to do so automatically.
SendingModeMdnSentAutomatically = SendingMode("mdn-sent-automatically")
// The message has been deleted.
//
// The recipient may or may not have seen the message.
//
// The recipient might "undelete" the message at a later time and read the message.
DispositionTypeOptionDeleted = DispositionTypeOption("deleted")
// The message has been sent somewhere in some manner (e.g., printed, faxed, forwarded) without
// necessarily having been previously displayed to the user.
//
// The user may or may not see the message later.
DispositionTypeOptionDispatched = DispositionTypeOption("dispatched")
// The message has been displayed by the MUA to someone reading the recipient's mailbox.
//
// There is no guarantee that the content has been read or understood.
DispositionTypeOptionDisplayed = DispositionTypeOption("displayed")
// The message has been processed in some manner (i.e., by some sort of rules or server)
// without being displayed to the user.
//
// The user may or may not see the message later, or there may not even be a human user
// associated with the mailbox.
DispositionTypeOptionProcessed = DispositionTypeOption("processed")
// All events are considered.
IncludeInAvailabilityAll = IncludeInAvailability("all")
// Events the user is a confirmed or tentative participant of are considered.
IncludeInAvailabilityAttending = IncludeInAvailability("attending")
// All events are ignored (but may be considered if also in another calendar).
IncludeInAvailabilityNone = IncludeInAvailability("none")
)
var (
ObjectTypes = []ObjectType{
CoreType,
PushSubscriptionType,
MailboxType,
ThreadType,
EmailType,
EmailDeliveryType,
SearchSnippetType,
IdentityType,
EmailSubmissionType,
VacationResponseType,
MDNType,
QuotaType,
SieveScriptType,
PrincipalType,
ShareNotificationType,
AddressBookType,
ContactCardType,
CalendarType,
CalendarEventType,
CalendarEventNotificationType,
ParticipantIdentityType,
}
JmapMailboxRoles = []string{
JmapMailboxRoleInbox,
JmapMailboxRoleSent,
JmapMailboxRoleDrafts,
JmapMailboxRoleJunk,
JmapMailboxRoleTrash,
}
CalendarEventNotificationOptionTypes = []CalendarEventNotificationTypeOption{
CalendarEventNotificationTypeOptionCreated,
CalendarEventNotificationTypeOptionUpdated,
CalendarEventNotificationTypeOptionDestroyed,
}
PrincipalTypeOptions = []PrincipalTypeOption{
PrincipalTypeOptionIndividual,
PrincipalTypeOptionGroup,
PrincipalTypeOptionResource,
PrincipalTypeOptionLocation,
PrincipalTypeOptionOther,
}
HttpDigestAlgorithms = []HttpDigestAlgorithm{
HttpDigestAlgorithmAdler32,
HttpDigestAlgorithmCrc32c,
HttpDigestAlgorithmMd5,
HttpDigestAlgorithmSha,
HttpDigestAlgorithmSha256,
HttpDigestAlgorithmSha512,
HttpDigestAlgorithmUnixSum,
HttpDigestAlgorithmUnixcksum,
}
ResourceTypes = []ResourceType{
ResourceTypeCount,
ResourceTypeOctets,
}
Scopes = []Scope{
ScopeAccount,
ScopeDomain,
ScopeGlobal,
}
ActionModes = []ActionMode{
ActionModeManualAction,
ActionModeAutomaticAction,
}
SendingModes = []SendingMode{
SendingModeMdnSentManually,
SendingModeMdnSentAutomatically,
}
DispositionTypeOptions = []DispositionTypeOption{
DispositionTypeOptionDeleted,
DispositionTypeOptionDispatched,
DispositionTypeOptionDisplayed,
DispositionTypeOptionProcessed,
}
IncludeInAvailabilities = []IncludeInAvailability{
IncludeInAvailabilityAll,
IncludeInAvailabilityAttending,
IncludeInAvailabilityNone,
}
)
type SessionMailAccountCapabilities struct {
// The maximum number of Mailboxes that can be can assigned to a single Email object.
//
// This MUST be an integer >= 1, or null for no limit (or rather, the limit is always
// the number of Mailboxes in the account).
MaxMailboxesPerEmail int `json:"maxMailboxesPerEmail"`
// The maximum depth of the Mailbox hierarchy (i.e., one more than the maximum
// number of ancestors a Mailbox may have), or null for no limit.
MaxMailboxDepth int `json:"maxMailboxDepth"`
// The maximum length, in (UTF-8) octets, allowed for the name of a Mailbox.
//
// This MUST be at least 100, although it is recommended servers allow more.
MaxSizeMailboxName int `json:"maxSizeMailboxName"`
// The maximum total size of attachments, in octets, allowed for a single Email object.
//
// A server MAY still reject the import or creation of an Email with a lower attachment size
// total (for example, if the body includes several megabytes of text, causing the size of
// the encoded MIME structure to be over some server-defined limit).
//
// Note that this limit is for the sum of unencoded attachment sizes. Users are generally
// not knowledgeable about encoding overhead, etc., nor should they need to be, so marketing
// and help materials normally tell them the “max size attachments”.
//
// This is the unencoded size they see on their hard drive, so this capability matches that
// and allows the client to consistently enforce what the user understands as the limit.
//
// The server may separately have a limit for the total size of the message [RFC5322],
// created by combining the attachments (often base64 encoded) with the message headers and bodies.
//
// For example, suppose the server advertises maxSizeAttachmentsPerEmail: 50000000 (50 MB).
// The enforced server limit may be for a message size of 70000000 octets.
// Even with base64 encoding and a 2 MB HTML body, 50 MB attachments would fit under this limit.
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
MaxSizeAttachmentsPerEmail int `json:"maxSizeAttachmentsPerEmail"`
// A list of all the values the server supports for the “property” field of the Comparator
// object in an Email/query sort.
//
// This MAY include properties the client does not recognise (for example, custom properties
// specified in a vendor extension). Clients MUST ignore any unknown properties in the list.
EmailQuerySortOptions []string `json:"emailQuerySortOptions"`
// If true, the user may create a Mailbox in this account with a null parentId.
//
// (Permission for creating a child of an existing Mailbox is given by the myRights property
// on that Mailbox.)
MayCreateTopLevelMailbox bool `json:"mayCreateTopLevelMailbox"`
}
type SessionSubmissionAccountCapabilities struct {
// The number in seconds of the maximum delay the server supports in sending.
//
// This is 0 if the server does not support delayed send.
MaxDelayedSend int `json:"maxDelayedSend"`
// The set of SMTP submission extensions supported by the server, which the client may use
// when creating an EmailSubmission object.
//
// Each key in the object is the ehlo-name, and the value is a list of ehlo-args.
//
// A JMAP implementation that talks to a submission server [RFC6409] SHOULD have a configuration
// setting that allows an administrator to modify the set of submission EHLO capabilities it may
// expose on this property.
//
// This allows a JMAP server to easily add access to a new submission extension without code changes.
//
// By default, the JMAP server should hide EHLO capabilities that have to do with the transport
// mechanism and thus are only relevant to the JMAP server (for example, PIPELINING, CHUNKING, or STARTTLS).
//
// Examples of Submission extensions to include:
// - FUTURERELEASE [RFC4865]
// - SIZE [RFC1870]
// - DSN [RFC3461]
// - DELIVERYBY [RFC2852]
// - MT-PRIORITY [RFC6710]
//
// A JMAP server MAY advertise an extension and implement the semantics of that extension locally
// on the JMAP server even if a submission server used by JMAP doesnt implement it.
//
// The full IANA registry of submission extensions can be found at [iana.org].
//
// [RFC6409]: https://www.rfc-editor.org/rfc/rfc6409.html
// [RFC4865]: https://www.rfc-editor.org/rfc/rfc4865.html
// [RFC1870]: https://www.rfc-editor.org/rfc/rfc1870.html
// [RFC3461]: https://www.rfc-editor.org/rfc/rfc3461.html
// [RFC2852]: https://www.rfc-editor.org/rfc/rfc2852.html
// [RFC6710]: https://www.rfc-editor.org/rfc/rfc6710.html
// [iana.org]: https://www.iana.org/assignments/mail-parameters
SubmissionExtensions map[string][]string `json:"submissionExtensions"`
}
// This represents support for the VacationResponse data type and associated API methods.
//
// The value of this property is an empty object in both the JMAP session capabilities
// property and an accounts accountCapabilities property.
type SessionVacationResponseAccountCapabilities struct {
}
type SessionSieveAccountCapabilities struct {
// The maximum length, in octets, allowed for the name of a SieveScript.
//
// For compatibility with ManageSieve, this MUST be at least 512 (up to 128 Unicode characters).
MaxSizeScriptName int `json:"maxSizeScriptName"`
// The maximum size (in octets) of a Sieve script the server is willing to store for the user,
// or null for no limit.
MaxSizeScript int `json:"maxSizeScript"`
// The maximum number of Sieve scripts the server is willing to store for the user, or null for no limit.
MaxNumberScripts int `json:"maxNumberScripts"`
// The maximum number of Sieve "redirect" actions a script can perform during a single evaluation,
// or null for no limit.
//
// Note that this is different from the total number of "redirect" actions a script can contain.
MaxNumberRedirects int `json:"maxNumberRedirects"`
// A list of case-sensitive Sieve capability strings (as listed in the Sieve "require" action;
// see [RFC5228, Section 3.2]) indicating the extensions supported by the Sieve engine.
//
// [RFC5228, Section 3.2]: https://www.rfc-editor.org/rfc/rfc5228.html#section-3.2
SieveExtensions []string `json:"sieveExtensions"`
// A list of URI scheme parts [RFC3986] for notification methods supported by the Sieve "enotify"
// extension [RFC5435], or null if the extension is not supported by the Sieve engine.
//
// [RFC3986]: https://www.rfc-editor.org/rfc/rfc3986.html
// [RFC5435]: https://www.rfc-editor.org/rfc/rfc5435.html
NotificationMethods []string `json:"notificationMethods"`
// A list of URI scheme parts [RFC3986] for externally stored list types supported by the
// Sieve "extlists" extension [RFC6134], or null if the extension is not supported by the Sieve engine.
//
// [RFC3986]: https://www.rfc-editor.org/rfc/rfc3986.html
// [RFC6134]: https://www.rfc-editor.org/rfc/rfc6134.html
ExternalLists []string `json:"externalLists"`
}
type SessionBlobAccountCapabilities struct {
// The maximum size of the blob (in octets) that the server will allow to be created
// (including blobs created by concatenating multiple data sources together).
//
// Clients MUST NOT attempt to create blobs larger than this size.
//
// If this value is null, then clients are not required to limit the size of the blob
// they try to create, though servers can always reject creation of blobs regardless of
// size, e.g., due to lack of disk space or per-user rate limits.
MaxSizeBlobSet int `json:"maxSizeBlobSet"`
// The maximum number of DataSourceObjects allowed per creation in a Blob/upload.
//
// Servers MUST allow at least 64 DataSourceObjects per creation.
MaxDataSources int `json:"maxDataSources"`
// An array of data type names that are supported for Blob/lookup.
//
// If the server does not support lookups, then this will be the empty list.
//
// Note that the supportedTypeNames list may include private types that are not in the
// "JMAP Data Types" registry defined by this document.
//
// Clients MUST ignore type names they do not recognise.
SupportedTypeNames []string `json:"supportedTypeNames"`
// An array of supported digest algorithms that are supported for Blob/get.
//
// If the server does not support calculating blob digests, then this will be the empty
// list.
//
// Algorithms in this list MUST be present in the ["HTTP Digest Algorithm Values" registry]
// defined by [RFC3230]; however, in JMAP, they must be lowercased, e.g., "md5" rather than
// "MD5".
//
// Clients SHOULD prefer algorithms listed earlier in this list.
//
// ["HTTP Digest Algorithm Values" registry]: https://www.iana.org/assignments/http-dig-alg/http-dig-alg.xhtml
SupportedDigestAlgorithms []HttpDigestAlgorithm `json:"supportedDigestAlgorithms"`
}
type SessionQuotaAccountCapabilities struct {
}
type SessionContactsAccountCapabilities struct {
// The maximum number of AddressBooks that can be can assigned to a single ContactCard object.
//
// This MUST be an integer >= 1, or null for no limit (or rather, the limit is always the number of AddressBooks
// in the account).
MaxAddressBooksPerCard uint `json:"maxAddressBooksPerCard,omitzero"`
// If true, the user may create an AddressBook in this account.
MayCreateAddressBook bool `json:"mayCreateAddressBook"`
}
type SessionCalendarsAccountCapabilities struct {
// The maximum number of Calendars that can be assigned to a single CalendarEvent object.
//
// This MUST be an integer >= 1, or null for no limit (or rather, the limit is always the
// number of Calendars in the account).
MaxCalendarsPerEvent *uint `json:"maxCalendarsPerEvent,omitempty"`
// The earliest date-time value the server is willing to accept for any date stored in a CalendarEvent.
MinDateTime *UTCDate `json:"minDateTime,omitempty"`
// The latest date-time value the server is willing to accept for any date stored in a CalendarEvent.
MaxDateTime *UTCDate `json:"maxDateTime,omitempty"`
// The maximum duration the user may query over when asking the server to expand recurrences.
MaxExpandedQueryDuration Duration `json:"maxExpandedQueryDuration,omitzero"`
// The maximum number of participants a single event may have, or null for no limit.
MaxParticipantsPerEvent *uint `json:"maxParticipantsPerEvent,omitzero"`
// If true, the user may create a calendar in this account.
MayCreateCalendar *bool `json:"mayCreateCalendar,omitempty"`
}
type SessionCalendarsParseAccountCapabilities struct {
}
type SessionTasksAccountCapabilities struct {
// The earliest date-time the server is willing to accept for any date stored in a Task.
MinDateTime LocalDate `json:"minDateTime,omitzero"`
// The latest date-time the server is willing to accept for any date stored in a Task.
MaxDateTime LocalDate `json:"maxDateTime,omitzero"`
// If true, the user may create a task list in this account.
MayCreateTaskList bool `json:"mayCreateTaskList"`
}
type SessionTasksRecurrencesAccountCapabilities struct {
// The maximum duration the user may query over when asking the server to expand recurrences.
MaxExpandedQueryDuration Duration `json:"maxExpandedQueryDuration"`
}
type SessionTasksAssigneesAccountCapabilities struct {
// The maximum number of participants a single task may have, or null for no limit.
MaxParticipantsPerTask *uint `json:"maxParticipantsPerTask,omitzero"`
}
type SessionTasksAlertsAccountCapabilities struct {
}
type SessionTasksMultilingualAccountCapabilities struct {
}
type SessionTasksCustomTimezonesAccountCapabilities struct {
}
type SessionPrincipalsAccountCapabilities struct {
// The id of the principal in this account that corresponds to the user fetching this object, if any.
CurrentUserPrincipalId string `json:"currentUserPrincipalId,omitempty"`
}
type SessionPrincipalsOwnerAccountCapabilities struct {
// The id of an account with the `urn:ietf:params:jmap:principals` capability that contains the
// corresponding `Principal` object.
AccountIdForPrincipal string `json:"accountIdForPrincipal,omitempty"`
// The id of the `Principal` that owns this account.
PrincipalId string `json:"principalId,omitempty"`
}
type SessionPrincipalAvailabilityAccountCapabilities struct {
// The maximum duration over which the server is prepared to calculate availability in a single call.
MaxAvailabilityDuration Duration `json:"maxAvailabilityDuration"`
}
type SessionMDNAccountCapabilities struct {
}
type SessionAccountCapabilities struct {
Mail *SessionMailAccountCapabilities `json:"urn:ietf:params:jmap:mail,omitempty"`
Submission *SessionSubmissionAccountCapabilities `json:"urn:ietf:params:jmap:submission,omitempty"`
VacationResponse *SessionVacationResponseAccountCapabilities `json:"urn:ietf:params:jmap:vacationresponse,omitempty"`
Sieve *SessionSieveAccountCapabilities `json:"urn:ietf:params:jmap:sieve,omitempty"`
Blob *SessionBlobAccountCapabilities `json:"urn:ietf:params:jmap:blob,omitempty"`
Quota *SessionQuotaAccountCapabilities `json:"urn:ietf:params:jmap:quota,omitempty"`
Contacts *SessionContactsAccountCapabilities `json:"urn:ietf:params:jmap:contacts,omitempty"`
Calendars *SessionCalendarsAccountCapabilities `json:"urn:ietf:params:jmap:calendars,omitempty"`
CalendarsParse *SessionCalendarsParseAccountCapabilities `json:"urn:ietf:params:jmap:calendars:parse,omitempty"`
Tasks *SessionTasksAccountCapabilities `json:"urn:ietf:params:jmap:tasks,omitempty"`
TasksRecurrences *SessionTasksRecurrencesAccountCapabilities `json:"urn:ietf:params:jmap:tasks:recurrences,omitempty"`
TasksAssignees *SessionTasksAssigneesAccountCapabilities `json:"urn:ietf:params:jmap:tasks:assignees,omitempty"`
TasksAlerts *SessionTasksAlertsAccountCapabilities `json:"urn:ietf:params:jmap:tasks:alerts,omitempty"`
TasksMultilingual *SessionTasksMultilingualAccountCapabilities `json:"urn:ietf:params:jmap:tasks:multilingual,omitempty"`
TasksCustomTimezones *SessionTasksCustomTimezonesAccountCapabilities `json:"urn:ietf:params:jmap:tasks:customtimezones,omitempty"`
Principals *SessionPrincipalsAccountCapabilities `json:"urn:ietf:params:jmap:principals,omitempty"`
PrincipalsOwner *SessionPrincipalsOwnerAccountCapabilities `json:"urn:ietf:params:jmap:principals:owner,omitempty"`
PrincipalsAvailability *SessionPrincipalAvailabilityAccountCapabilities `json:"urn:ietf:params:jmap:principals:availability,omitempty"`
MDN *SessionMDNAccountCapabilities `json:"urn:ietf:params:jmap:mdn,omitempty"`
}
type Account struct {
// A user-friendly string to show when presenting content from this account, e.g., the email address representing the owner of the account.
Name string `json:"name,omitempty"`
// This is true if the account belongs to the authenticated user rather than a group account or a personal account of another user that has been shared with them.
IsPersonal bool `json:"isPersonal"`
// This is true if the entire account is read-only.
IsReadOnly bool `json:"isReadOnly"`
// Account capabilities.
AccountCapabilities SessionAccountCapabilities `json:"accountCapabilities"`
}
type SessionCoreCapabilities struct {
// The maximum file size, in octets, that the server will accept for a single file upload (for any purpose)
MaxSizeUpload int `json:"maxSizeUpload"`
// The maximum number of concurrent requests the server will accept to the upload endpoint.
MaxConcurrentUpload int `json:"maxConcurrentUpload"`
// The maximum size, in octets, that the server will accept for a single request to the API endpoint.
MaxSizeRequest int `json:"maxSizeRequest"`
// The maximum number of concurrent requests the server will accept to the API endpoint.
MaxConcurrentRequests int `json:"maxConcurrentRequests"`
// The maximum number of method calls the server will accept in a single request to the API endpoint.
MaxCallsInRequest int `json:"maxCallsInRequest"`
// The maximum number of objects that the client may request in a single /get type method call.
MaxObjectsInGet int `json:"maxObjectsInGet"`
// The maximum number of objects the client may send to create, update, or destroy in a single /set type method call.
// This is the combined total, e.g., if the maximum is 10, you could not create 7 objects and destroy 6, as this would be 13 actions,
// which exceeds the limit.
MaxObjectsInSet int `json:"maxObjectsInSet"`
// A list of identifiers for algorithms registered in the collation registry, as defined in [@!RFC4790], that the server
// supports for sorting when querying records.
CollationAlgorithms []string `json:"collationAlgorithms,omitempty"`
}
type SessionMailCapabilities struct {
}
type SessionSubmissionCapabilities struct {
}
type SessionVacationResponseCapabilities struct {
}
type SessionSieveCapabilities struct {
}
type SessionBlobCapabilities struct {
}
type SessionQuotaCapabilities struct {
}
type SessionWebsocketCapabilities struct {
// The wss-URI (see [Section 3 of RFC6455]) to use for initiating a JMAP-over-WebSocket
// handshake (the "WebSocket URL endpoint" colloquially).
//
// [Section 3 of RFC6455]: https://www.rfc-editor.org/rfc/rfc6455.html#section-3
Url string `json:"url"`
// This is true if the server supports push notifications over the WebSocket,
// as described in [Section 4.3.5 of RFC 8887].
//
// [Section 4.3.5 of RFC 8887]: https://www.rfc-editor.org/rfc/rfc8887.html#name-jmap-push-notifications
SupportsPush bool `json:"supportsPush"`
}
type SessionContactsCapabilities struct {
}
type SessionCalendarsCapabilities struct {
}
type SessionCalendarsParseCapabilities struct {
}
type SessionTasksCapabilities struct {
}
type SessionTasksRecurrencesCapabilities struct {
}
type SessionTasksAssigneesCapabilities struct {
}
type SessionTasksAlertsCapabilities struct {
}
type SessionTasksMultilingualCapabilities struct {
}
type SessionTasksCustomTimezonesCapabilities struct {
}
type SessionPrincipalCapabilities struct {
// Id of Account with the urn:ietf:params:jmap:calendars capability that contains the calendar data
// for this Principal, or null if either (a) there is none (e.g. the Principal is a group just used
// for permissions management), or (b) the user does not have access to any data in the account
// (with the exception of free/busy, which is governed by the "mayGetAvailability" property).
//
// The corresponding Account object can be found in the Principal's "accounts" property, as
// per Section 2 of [RFC9670].
AccountId string `json:"accountId,omitempty"`
// If true, the user may call the "Principal/getAvailability" method with this Principal.
MayGetAvailability *bool `json:"mayGetAvailability,omitzero"`
// If true, the user may add this Principal as a calendar share target (by adding them to the
// "shareWith" property of a calendar, see Section 4).
MayShareWith *bool `json:"mayShareWith,omitzero"`
// If this Principal may be added as a participant to an event, this is the calendarAddress to
// use to receive iTIP scheduling messages.
CalendarAddress string `json:"calendarAddress,omitempty"`
}
type SessionPrincipalAvailabilityCapabilities struct {
}
type SessionMDNCapabilities struct {
}
type SessionCapabilities struct {
Core *SessionCoreCapabilities `json:"urn:ietf:params:jmap:core,omitempty"`
Mail *SessionMailCapabilities `json:"urn:ietf:params:jmap:mail,omitempty"`
Submission *SessionSubmissionCapabilities `json:"urn:ietf:params:jmap:submission,omitempty"`
VacationResponse *SessionVacationResponseCapabilities `json:"urn:ietf:params:jmap:vacationresponse,omitempty"`
Sieve *SessionSieveCapabilities `json:"urn:ietf:params:jmap:sieve,omitempty"`
Blob *SessionBlobCapabilities `json:"urn:ietf:params:jmap:blob,omitempty"`
Quota *SessionQuotaCapabilities `json:"urn:ietf:params:jmap:quota,omitempty"`
Websocket *SessionWebsocketCapabilities `json:"urn:ietf:params:jmap:websocket,omitempty"`
// This represents support for the `AddressBook` and `ContactCard` data types and associated API methods.
//
// The value of this property in the JMAP Session `capabilities` property is an empty object.
Contacts *SessionContactsCapabilities `json:"urn:ietf:params:jmap:contacts,omitempty"`
// This represents support for the `Calendar`, `CalendarEvent`, `CalendarEventNotification`,
// and `ParticipantIdentity` data types and associated API methods, except for `CalendarEvent/parse`.
//
// The value of this property in the JMAP Session `capabilities` property is an empty object.
Calendars *SessionCalendarsCapabilities `json:"urn:ietf:params:jmap:calendars,omitempty"`
// This represents support for the `CalendarEvent/parse` method.
//
// The value of this property is an empty object in the JMAP session `capabilities` property.
CalendarsParse *SessionCalendarsParseCapabilities `json:"urn:ietf:params:jmap:calendars:parse,omitempty"`
// This represents support for the core properties and objects of the `TaskList`,
// `Task` and `TaskNotification` data types and associated API methods.
//
// The value of this property in the JMAP Session `capabilities` property is an empty object.
Tasks *SessionTasksCapabilities `json:"urn:ietf:params:jmap:tasks,omitempty"`
// This represents support for the `recurrence` properties and objects of the `TaskList`,
// `Task` and `TaskNotification` data types and associated API methods.
//
// The value of this property in the JMAP Session `capabilities` property is an empty object.
TasksRecurrences *SessionTasksRecurrencesCapabilities `json:"urn:ietf:params:jmap:tasks:recurrences,omitempty"`
// This represents support for the `assignee` properties and objects of the `TaskList`,
// `Task` and `TaskNotification` data types and associated API methods.
//
// The value of this property in the JMAP Session `capabilities` property is an empty object.
TasksAssignees *SessionTasksAssigneesCapabilities `json:"urn:ietf:params:jmap:tasks:assignees,omitempty"`
// This represents support for the `alerts` properties and objects of the `TaskList`,
// `Task` and `TaskNotification` data types and associated API methods.
//
// The value of this property in the JMAP Session `capabilities` property is an empty object.
TasksAlerts *SessionTasksAlertsCapabilities `json:"urn:ietf:params:jmap:tasks:alerts,omitempty"`
// This represents support for the multilingual properties and objects of the `TaskList`,
// `Task` and `TaskNotification` data types and associated API methods.
//
// The value of this property in the JMAP Session `capabilities` property is an empty object.
TasksMultilingual *SessionTasksMultilingualCapabilities `json:"urn:ietf:params:jmap:tasks:multilingual,omitempty"`
// This represents support for the custom time zone properties and objects of the `TaskList`,
// `Task` and `TaskNotification` data types and associated API methods.
//
// The value of this property in the JMAP Session `capabilities` property is an empty object.
TasksCustomTimezones *SessionTasksCustomTimezonesCapabilities `json:"urn:ietf:params:jmap:tasks:customtimezones,omitempty"`
Principals *SessionPrincipalCapabilities `json:"urn:ietf:params:jmap:principals,omitempty"`
// Represents support for the `Principal/getAvailability` method.
//
// Any account with this capability MUST also have the `urn:ietf:params:jmap:principals` capability.
//
// The value of this property in the JMAP Session `capabilities` property is an empty object.
PrincipalsAvailability *SessionPrincipalAvailabilityCapabilities `json:"urn:ietf:params:jmap:principals:availability,omitempty"`
MDN *SessionMDNCapabilities `json:"urn:ietf:params:jmap:mdn,omitempty"`
}
type SessionPrimaryAccounts struct {
Core string `json:"urn:ietf:params:jmap:core,omitempty"`
Mail string `json:"urn:ietf:params:jmap:mail,omitempty"`
Submission string `json:"urn:ietf:params:jmap:submission,omitempty"`
VacationResponse string `json:"urn:ietf:params:jmap:vacationresponse,omitempty"`
Sieve string `json:"urn:ietf:params:jmap:sieve,omitempty"`
Blob string `json:"urn:ietf:params:jmap:blob,omitempty"`
Quota string `json:"urn:ietf:params:jmap:quota,omitempty"`
Websocket string `json:"urn:ietf:params:jmap:websocket,omitempty"`
Task string `json:"urn:ietf:params:jmap:task,omitempty"`
Calendars string `json:"urn:ietf:params:jmap:calendars,omitempty"`
CalendarsParse string `json:"urn:ietf:params:jmap:calendars:parse,omitempty"`
Contacts string `json:"urn:ietf:params:jmap:contacts,omitempty"`
ContactsParse string `json:"urn:ietf:params:jmap:contacts:parse,omitempty"`
}
type SessionState string
type State string
type Language string
type SessionResponse struct {
Capabilities SessionCapabilities `json:"capabilities"`
Accounts map[string]Account `json:"accounts,omitempty"`
// A map of capability URIs (as found in accountCapabilities) to the account id that is considered to be the users main or default
// account for data pertaining to that capability.
// If no account being returned belongs to the user, or in any other way there is no appropriate way to determine a default account,
// there MAY be no entry for a particular URI, even though that capability is supported by the server (and in the capabilities object).
// urn:ietf:params:jmap:core SHOULD NOT be present.
PrimaryAccounts SessionPrimaryAccounts `json:"primaryAccounts"`
// The username associated with the given credentials, or the empty string if none.
Username string `json:"username,omitempty"`
// The URL to use for JMAP API requests.
ApiUrl string `json:"apiUrl,omitempty"`
// The URL endpoint to use when downloading files, in URI Template (level 1) format [@!RFC6570].
// The URL MUST contain variables called accountId, blobId, type, and name.
DownloadUrl string `json:"downloadUrl,omitempty"`
// The URL endpoint to use when uploading files, in URI Template (level 1) format [@!RFC6570].
// The URL MUST contain a variable called accountId.
UploadUrl string `json:"uploadUrl,omitempty"`
// The URL to connect to for push events, as described in Section 7.3, in URI Template (level 1) format [@!RFC6570].
// The URL MUST contain variables called types, closeafter, and ping.
EventSourceUrl string `json:"eventSourceUrl,omitempty"`
// A (preferably short) string representing the state of this object on the server.
// If the value of any other property on the Session object changes, this string will change.
// The current value is also returned on the API Response object (see Section 3.4), allowing clients to quickly
// determine if the session information has changed (e.g., an account has been added or removed),
// so they need to refetch the object.
State SessionState `json:"state,omitempty"`
}
// Method level error types.
const (
// Some internal server resource was temporarily unavailable.
//
// Attempting the same operation later (perhaps after a backoff with a random factor) may succeed.
MethodLevelErrorServerUnavailable = "serverUnavailable"
// An unexpected or unknown error occurred during the processing of the call.
//
// A description property should provide more details about the error. The method call made no changes
// to the servers state. Attempting the same operation again is expected to fail again.
// Contacting the service administrator is likely necessary to resolve this problem if it is persistent.
MethodLevelErrorServerFail = "serverFail"
// Some, but not all, expected changes described by the method occurred.
//
// The client MUST resynchronise impacted data to determine server state. Use of this error is strongly discouraged.
MethodLevelErrorServerPartialFail = "serverPartialFail"
// The server does not recognise this method name.
MethodLevelErrorUnknownMethod = "unknownMethod"
// One of the arguments is of the wrong type or is otherwise invalid, or a required argument is missing.
//
// A description property MAY be present to help debug with an explanation of what the problem was.
// This is a non-localised string, and it is not intended to be shown directly to end users.
MethodLevelErrorInvalidArguments = "invalidArguments"
// The method used a result reference for one of its arguments, but this failed to resolve.
MethodLevelErrorInvalidResultReference = "invalidResultReference"
// The method and arguments are valid, but executing the method would violate an Access Control List
// (ACL) or other permissions policy.
MethodLevelErrorForbidden = "forbidden"
// The accountId does not correspond to a valid account.
MethodLevelErrorAccountNotFound = "accountNotFound"
// The accountId given corresponds to a valid account, but the account does not support this method or data type.
MethodLevelErrorAccountNotSupportedByMethod = "accountNotSupportedByMethod"
// This method modifies state, but the account is read-only (as returned on the corresponding Account object in
// the JMAP Session resource).
MethodLevelErrorAccountReadOnly = "accountReadOnly"
)
// SetError type values.
const (
// The create/update/destroy would violate an ACL or other permissions policy.
//
// (create; update; destroy).
SetErrorTypeForbidden = "forbidden"
// The create would exceed a server-defined limit on the number or total size of objects of this type.
//
// (create; update).
SetErrorTypeOverQuota = "overQuota"
// The create/update would result in an object that exceeds a server-defined limit for the maximum
// size of a single object of this type.
//
// (create; update).
SetErrorTypeTooLarge = "tooLarge"
// Too many objects of this type have been created recently, and a server-defined rate limit has been reached.
// It may work if tried again later.
//
// (create).
SetErrorTypeRateLimit = "rateLimit"
// The id given to update/destroy cannot be found.
//
// (update; destroy).
SetErrorTypeNotFound = "notFound"
// The PatchObject given to update the record was not a valid patch (see the patch description).
//
// (update).
SetErrorTypeInvalidPatch = "invalidPatch"
// The client requested that an object be both updated and destroyed in the same /set request, and the server
// has decided to therefore ignore the update.
//
// (update).
SetErrorTypeWillDestroy = "willDestroy"
// The record given is invalid in some way. For example:
//
// - It contains properties that are invalid according to the type specification of this record type.
// - It contains a property that may only be set by the server (e.g., “id”) and is different to the current value.
// Note, to allow clients to pass whole objects back, it is not an error to include a server-set property in an
// update as long as the value is identical to the current value on the server.
// - There is a reference to another record (foreign key), and the given id does not correspond to a valid record.
//
// The SetError object SHOULD also have a property called properties of type String[] that lists all the properties
// that were invalid.
//
// Individual methods MAY specify more specific errors for certain conditions that would otherwise result in an
// invalidProperties error. If the condition of one of these is met, it MUST be returned instead of the invalidProperties error.
//
// (create; update).
SetErrorTypeInvalidProperties = "invalidProperties"
// This is a singleton type, so you cannot create another one or destroy the existing one.
//
// (create; destroy).
SetErrorTypeSingleton = "singleton"
// The total number of objects to create, update, or destroy exceeds the maximum number the server is
// willing to process in a single method call.
SetErrorTypeRequestTooLarge = "requestTooLarge"
// An ifInState argument was supplied, and it does not match the current state.
SetErrorTypeStateMismatch = "stateMismatch"
// The Email to be sent is invalid in some way.
//
// The SetError SHOULD contain a property called properties of type String[] that lists all the properties
// of the Email that were invalid.
SetErrorInvalidEmail = "invalidEmail"
// The envelope (supplied or generated) has more recipients than the server allows.
//
// A maxRecipients UnsignedInt property MUST also be present on the SetError specifying
// the maximum number of allowed recipients.
SetErrorTooManyRecipients = "tooManyRecipients"
// The envelope (supplied or generated) does not have any rcptTo email addresses.
SetErrorNoRecipients = "noRecipients"
// The rcptTo property of the envelope (supplied or generated) contains at least one rcptTo value which
// is not a valid email address for sending to.
//
// An invalidRecipients String[] property MUST also be present on the SetError, which is a list of the invalid addresses.
SetErrorInvalidRecipients = "invalidRecipients"
// The server does not permit the user to send a message with this envelope From address [RFC5321].
//
// [RFC5321]: https://datatracker.ietf.org/doc/html/rfc5321
SetErrorForbiddenMailFrom = "forbiddenMailFrom"
// The server does not permit the user to send a message with the From header field [RFC5322] of the message to be sent.
//
// [RFC5322]: https://datatracker.ietf.org/doc/html/rfc5322
SetErrorForbiddenFrom = "forbiddenFrom"
// The user does not have permission to send at all right now for some reason.
//
// A description String property MAY be present on the SetError object to display to the user why they are not permitted.
SetErrorForbiddenToSend = "forbiddenToSend"
// The message has the `$mdnsent` keyword already set.
SetErrorMdnAlreadySent = "mdnAlreadySent"
)
type SetError struct {
// The type of error.
Type string `json:"type"`
// A description of the error to help with debugging that includes an explanation of what the problem was.
//
// This is a non-localised string and is not intended to be shown directly to end users.
Description string `json:"description,omitempty"`
// Lists all the properties of the Email that were invalid.
//
// Only set for the invalidEmail error after a failed EmailSubmission/set errors.
Properties []string `json:"properties,omitempty"`
// Specifies the maximum number of allowed recipients.
//
// Only set for the tooManyRecipients error after a failed EmailSubmission/set errors.
MaxRecipients int `json:"maxRecipients,omitzero"`
// List of invalid addresses.
//
// Only set for the invalidRecipients error after a failed EmailSubmission/set errors.
InvalidRecipients []string `json:"invalidRecipients,omitempty"`
}
type FilterOperatorTerm string
const (
And FilterOperatorTerm = "AND"
Or FilterOperatorTerm = "OR"
Not FilterOperatorTerm = "NOT"
)
type MailboxRights struct {
// If true, the user may use this Mailbox as part of a filter in an Email/query call,
// and the Mailbox may be included in the mailboxIds property of Email objects.
//
// Email objects may be fetched if they are in at least one Mailbox with this permission.
//
// If a sub-Mailbox is shared but not the parent Mailbox, this may be false.
//
// Corresponds to IMAP ACLs lr (if mapping from IMAP, both are required for this to be true).
MayReadItems bool `json:"mayReadItems"`
// The user may add mail to this Mailbox (by either creating a new Email or moving an existing one).
//
// Corresponds to IMAP ACL i.
MayAddItems bool `json:"mayAddItems"`
// The user may remove mail from this Mailbox (by either changing the Mailboxes of an Email or
// destroying the Email).
//
// Corresponds to IMAP ACLs te (if mapping from IMAP, both are required for this to be true).
MayRemoveItems bool `json:"mayRemoveItems"`
// The user may add or remove the $seen keyword to/from an Email.
//
// If an Email belongs to multiple Mailboxes, the user may only modify $seen if they have this
// permission for all of the Mailboxes.
//
// Corresponds to IMAP ACL s.
MaySetSeen bool `json:"maySetSeen"`
// The user may add or remove any keyword other than $seen to/from an Email.
//
// If an Email belongs to multiple Mailboxes, the user may only modify keywords if they have this
// permission for all of the Mailboxes.
//
// Corresponds to IMAP ACL w.
MaySetKeywords bool `json:"maySetKeywords"`
// The user may create a Mailbox with this Mailbox as its parent.
//
// Corresponds to IMAP ACL k.
MayCreateChild bool `json:"mayCreateChild"`
// The user may rename the Mailbox or make it a child of another Mailbox.
//
// Corresponds to IMAP ACL x (although this covers both rename and delete permissions).
MayRename bool `json:"mayRename"`
// The user may delete the Mailbox itself.
//
// Corresponds to IMAP ACL x (although this covers both rename and delete permissions).
MayDelete bool `json:"mayDelete"`
// Messages may be submitted directly to this Mailbox.
//
// Corresponds to IMAP ACL p.
MaySubmit bool `json:"maySubmit"`
}
type Mailbox struct {
// The id of the Mailbox.
Id string `json:"id,omitempty"`
// User-visible name for the Mailbox, e.g., “Inbox”.
//
// This MUST be a Net-Unicode string [@!RFC5198] of at least 1 character in length, subject to the maximum size
// given in the capability object.
//
// There MUST NOT be two sibling Mailboxes with both the same parent and the same name.
//
// Servers MAY reject names that violate server policy (e.g., names containing a slash (/) or control characters).
Name string `json:"name,omitempty"`
// The Mailbox id for the parent of this Mailbox, or null if this Mailbox is at the top level.
//
// Mailboxes form acyclic graphs (forests) directed by the child-to-parent relationship. There MUST NOT be a loop.
ParentId string `json:"parentId,omitempty"`
// Identifies Mailboxes that have a particular common purpose (e.g., the “inbox”), regardless of the name property
// (which may be localised).
//
// This value is shared with IMAP (exposed in IMAP via the SPECIAL-USE extension [RFC6154]).
// However, unlike in IMAP, a Mailbox MUST only have a single role, and there MUST NOT be two Mailboxes in the same
// account with the same role.
//
// Servers providing IMAP access to the same data are encouraged to enforce these extra restrictions in IMAP as well.
// Otherwise, modifying the IMAP attributes to ensure compliance when exposing the data over JMAP is implementation dependent.
//
// The value MUST be one of the Mailbox attribute names listed in the IANA IMAP Mailbox Name Attributes registry,
// as established in [RFC8457], converted to lowercase. New roles may be established here in the future.
//
// An account is not required to have Mailboxes with any particular roles.
//
// [RFC6154]: https://www.rfc-editor.org/rfc/rfc6154.html
// [RFC8457]: https://www.rfc-editor.org/rfc/rfc8457.html
Role string `json:"role,omitempty"`
// Defines the sort order of Mailboxes when presented in the clients UI, so it is consistent between devices.
//
// Default value: 0
//
// The number MUST be an integer in the range 0 <= sortOrder < 2^31.
//
// A Mailbox with a lower order should be displayed before a Mailbox with a higher order
// (that has the same parent) in any Mailbox listing in the clients UI.
// Mailboxes with equal order SHOULD be sorted in alphabetical order by name.
// The sorting should take into account locale-specific character order convention.
SortOrder *int `json:"sortOrder,omitempty"`
// The number of Emails in this Mailbox.
TotalEmails int `json:"totalEmails"`
// The number of Emails in this Mailbox that have neither the $seen keyword nor the $draft keyword.
UnreadEmails int `json:"unreadEmails"`
// The number of Threads where at least one Email in the Thread is in this Mailbox.
TotalThreads int `json:"totalThreads"`
// An indication of the number of “unread” Threads in the Mailbox.
UnreadThreads int `json:"unreadThreads"`
// The set of rights (Access Control Lists (ACLs)) the user has in relation to this Mailbox.
//
// These are backwards compatible with IMAP ACLs, as defined in [RFC4314].
//
// [RFC4314]: https://www.rfc-editor.org/rfc/rfc4314.html
MyRights *MailboxRights `json:"myRights,omitempty"`
// Has the user indicated they wish to see this Mailbox in their client?
//
// This SHOULD default to false for Mailboxes in shared accounts the user has access to and true
// for any new Mailboxes created by the user themself.
//
// This MUST be stored separately per user where multiple users have access to a shared Mailbox.
//
// A user may have permission to access a large number of shared accounts, or a shared account with a very
// large set of Mailboxes, but only be interested in the contents of a few of these.
//
// Clients may choose to only display Mailboxes where the isSubscribed property is set to true, and offer
// a separate UI to allow the user to see and subscribe/unsubscribe from the full set of Mailboxes.
//
// However, clients MAY choose to ignore this property, either entirely for ease of implementation or just
// for an account where isPersonal is true (indicating it is the users own rather than a shared account).
//
// This property corresponds to IMAP [RFC3501] Mailbox subscriptions.
//
// [RFC3501]: https://www.rfc-editor.org/rfc/rfc3501.html
IsSubscribed *bool `json:"isSubscribed,omitempty"`
}
type MailboxChange struct {
// User-visible name for the Mailbox, e.g., “Inbox”.
//
// This MUST be a Net-Unicode string [@!RFC5198] of at least 1 character in length, subject to the maximum size
// given in the capability object.
//
// There MUST NOT be two sibling Mailboxes with both the same parent and the same name.
//
// Servers MAY reject names that violate server policy (e.g., names containing a slash (/) or control characters).
Name string `json:"name,omitempty"`
// The Mailbox id for the parent of this Mailbox, or null if this Mailbox is at the top level.
//
// Mailboxes form acyclic graphs (forests) directed by the child-to-parent relationship. There MUST NOT be a loop.
ParentId string `json:"parentId,omitempty"`
// Identifies Mailboxes that have a particular common purpose (e.g., the “inbox”), regardless of the name property
// (which may be localised).
//
// This value is shared with IMAP (exposed in IMAP via the SPECIAL-USE extension [RFC6154]).
// However, unlike in IMAP, a Mailbox MUST only have a single role, and there MUST NOT be two Mailboxes in the same
// account with the same role.
//
// Servers providing IMAP access to the same data are encouraged to enforce these extra restrictions in IMAP as well.
// Otherwise, modifying the IMAP attributes to ensure compliance when exposing the data over JMAP is implementation dependent.
//
// The value MUST be one of the Mailbox attribute names listed in the IANA IMAP Mailbox Name Attributes registry,
// as established in [RFC8457], converted to lowercase. New roles may be established here in the future.
//
// An account is not required to have Mailboxes with any particular roles.
//
// [RFC6154]: https://www.rfc-editor.org/rfc/rfc6154.html
// [RFC8457]: https://www.rfc-editor.org/rfc/rfc8457.html
Role string `json:"role,omitempty"`
// Defines the sort order of Mailboxes when presented in the clients UI, so it is consistent between devices.
//
// Default value: 0
//
// The number MUST be an integer in the range 0 <= sortOrder < 2^31.
//
// A Mailbox with a lower order should be displayed before a Mailbox with a higher order
// (that has the same parent) in any Mailbox listing in the clients UI.
// Mailboxes with equal order SHOULD be sorted in alphabetical order by name.
// The sorting should take into account locale-specific character order convention.
SortOrder *int `json:"sortOrder,omitempty"`
// Has the user indicated they wish to see this Mailbox in their client?
//
// This SHOULD default to false for Mailboxes in shared accounts the user has access to and true
// for any new Mailboxes created by the user themself.
//
// This MUST be stored separately per user where multiple users have access to a shared Mailbox.
//
// A user may have permission to access a large number of shared accounts, or a shared account with a very
// large set of Mailboxes, but only be interested in the contents of a few of these.
//
// Clients may choose to only display Mailboxes where the isSubscribed property is set to true, and offer
// a separate UI to allow the user to see and subscribe/unsubscribe from the full set of Mailboxes.
//
// However, clients MAY choose to ignore this property, either entirely for ease of implementation or just
// for an account where isPersonal is true (indicating it is the users own rather than a shared account).
//
// This property corresponds to IMAP [RFC3501] Mailbox subscriptions.
//
// [RFC3501]: https://www.rfc-editor.org/rfc/rfc3501.html
IsSubscribed *bool `json:"isSubscribed,omitempty"`
}
func (m MailboxChange) AsPatch() PatchObject {
p := PatchObject{}
if m.Name != "" {
p["name"] = m.Name
}
if m.ParentId != "" {
p["parentId"] = m.ParentId
}
if m.Role != "" {
p["role"] = m.Role
}
if m.SortOrder != nil {
p["sortOrder"] = m.SortOrder
}
if m.IsSubscribed != nil {
p["isSubscribed"] = m.IsSubscribed
}
return p
}
type MailboxGetCommand struct {
AccountId string `json:"accountId"`
Ids []string `json:"ids,omitempty"`
}
type MailboxGetRefCommand struct {
AccountId string `json:"accountId"`
IdsRef *ResultReference `json:"#ids,omitempty"`
}
type MailboxSetCommand struct {
AccountId string `json:"accountId"`
IfInState string `json:"ifInState,omitempty"`
Create map[string]MailboxChange `json:"create,omitempty"`
Update map[string]PatchObject `json:"update,omitempty"`
Destroy []string `json:"destroy,omitempty"`
}
type MailboxSetResponse struct {
AccountId string `json:"accountId"`
OldState State `json:"oldState,omitempty"`
NewState State `json:"newState,omitempty"`
Created map[string]Mailbox `json:"created,omitempty"`
Updated map[string]Mailbox `json:"updated,omitempty"`
Destroyed []string `json:"destroyed,omitempty"`
NotCreated map[string]SetError `json:"notCreated,omitempty"`
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
NotDestroyed map[string]SetError `json:"notDestroyed,omitempty"`
}
type MailboxChangesCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// The current state of the client.
//
// This is the string that was returned as the state argument in the Mailbox/get response.
//
// The server will return the changes that have occurred since this state.
SinceState string `json:"sinceState,omitempty"`
// The maximum number of ids to return in the response.
//
// The server MAY choose to return fewer than this value but MUST NOT return more.
//
// If not given by the client, the server may choose how many to return.
//
// If supplied by the client, the value MUST be a positive integer greater than 0.
//
// If a value outside of this range is given, the server MUST reject the call with an invalidArguments error.
MaxChanges uint `json:"maxChanges,omitzero"`
}
type MailboxFilterElement interface {
_isAMailboxFilterElement() // marker method
}
type MailboxFilterCondition struct {
ParentId string `json:"parentId,omitempty"`
Name string `json:"name,omitempty"`
Role string `json:"role,omitempty"`
HasAnyRole *bool `json:"hasAnyRole,omitempty"`
IsSubscribed *bool `json:"isSubscribed,omitempty"`
}
func (c MailboxFilterCondition) _isAMailboxFilterElement() {}
var _ MailboxFilterElement = &MailboxFilterCondition{}
type MailboxFilterOperator struct {
Operator FilterOperatorTerm `json:"operator"`
Conditions []MailboxFilterElement `json:"conditions,omitempty"`
}
func (c MailboxFilterOperator) _isAMailboxFilterElement() {}
var _ MailboxFilterElement = &MailboxFilterOperator{}
type MailboxComparator struct {
Property string `json:"property"`
IsAscending bool `json:"isAscending,omitempty"`
Limit int `json:"limit,omitzero"`
CalculateTotal bool `json:"calculateTotal,omitempty"`
}
type MailboxQueryCommand struct {
AccountId string `json:"accountId"`
Filter MailboxFilterElement `json:"filter,omitempty"`
Sort []MailboxComparator `json:"sort,omitempty"`
SortAsTree bool `json:"sortAsTree,omitempty"`
FilterAsTree bool `json:"filterAsTree,omitempty"`
}
type EmailFilterElement interface {
_isAnEmailFilterElement() // marker method
IsNotEmpty() bool
}
type EmailFilterCondition struct {
// A Mailbox id.
//
// An Email must be in this Mailbox to match the condition.
InMailbox string `json:"inMailbox,omitempty"`
// A list of Mailbox ids.
//
// An Email must be in at least one Mailbox not in this list to match the condition.
//
// This is to allow messages solely in trash/spam to be easily excluded from a search.
InMailboxOtherThan []string `json:"inMailboxOtherThan,omitempty"`
// The receivedAt date-time of the Email must be before this date-time to match
// the condition.
Before time.Time `json:"before,omitzero"` // omitzero requires Go 1.24
// The receivedAt date-time of the Email must be the same or after this date-time
// to match the condition.
After time.Time `json:"after,omitzero"`
// The size property of the Email must be equal to or greater than this number to match
// the condition.
MinSize int `json:"minSize,omitempty"`
// The size property of the Email must be less than this number to match the condition.
MaxSize int `json:"maxSize,omitempty"`
// All Emails (including this one) in the same Thread as this Email must have the given
// keyword to match the condition.
AllInThreadHaveKeyword string `json:"allInThreadHaveKeyword,omitempty"`
// At least one Email (possibly this one) in the same Thread as this Email must have the
// given keyword to match the condition.
SomeInThreadHaveKeyword string `json:"someInThreadHaveKeyword,omitempty"`
// All Emails (including this one) in the same Thread as this Email must not have the
// given keyword to match the condition.
NoneInThreadHaveKeyword string `json:"noneInThreadHaveKeyword,omitempty"`
// This Email must have the given keyword to match the condition.
HasKeyword string `json:"hasKeyword,omitempty"`
// This Email must not have the given keyword to match the condition.
NotKeyword string `json:"notKeyword,omitempty"`
// The hasAttachment property of the Email must be identical to the value given to match
// the condition.
HasAttachment bool `json:"hasAttachment,omitempty"`
// Looks for the text in Emails.
//
// The server MUST look up text in the From, To, Cc, Bcc, and Subject header fields of the
// message and SHOULD look inside any text/* or other body parts that may be converted to
// text by the server.
//
// The server MAY extend the search to any additional textual property.
Text string `json:"text,omitempty"`
// Looks for the text in the From header field of the message.
From string `json:"from,omitempty"`
// Looks for the text in the To header field of the message.
To string `json:"to,omitempty"`
// Looks for the text in the Cc header field of the message.
Cc string `json:"cc,omitempty"`
// Looks for the text in the Bcc header field of the message.
Bcc string `json:"bcc,omitempty"`
// Looks for the text in the Subject header field of the message.
Subject string `json:"subject,omitempty"`
// Looks for the text in one of the body parts of the message.
//
// The server MAY exclude MIME body parts with content media types other than text/*
// and message/* from consideration in search matching.
//
// Care should be taken to match based on the text content actually presented to an end user
// by viewers for that media type or otherwise identified as appropriate for search indexing.
//
// Matching document metadata uninteresting to an end user (e.g., markup tag and attribute
// names) is undesirable.
Body string `json:"body,omitempty"`
// The array MUST contain either one or two elements.
//
// The first element is the name of the header field to match against.
//
// The second (optional) element is the text to look for in the header field value.
//
// If not supplied, the message matches simply if it has a header field of the given name.
Header []string `json:"header,omitempty"`
}
func (f EmailFilterCondition) _isAnEmailFilterElement() {
}
func (f EmailFilterCondition) IsNotEmpty() bool {
if !f.After.IsZero() {
return true
}
if f.AllInThreadHaveKeyword != "" {
return true
}
if len(f.Bcc) > 0 {
return true
}
if !f.Before.IsZero() {
return true
}
if f.Body != "" {
return true
}
if f.Cc != "" {
return true
}
if f.From != "" {
return true
}
if f.HasAttachment {
return true
}
if f.HasKeyword != "" {
return true
}
if len(f.Header) > 0 {
return true
}
if f.InMailbox != "" {
return true
}
if len(f.InMailboxOtherThan) > 0 {
return true
}
if f.MaxSize != 0 {
return true
}
if f.MinSize != 0 {
return true
}
if f.NoneInThreadHaveKeyword != "" {
return true
}
if f.NotKeyword != "" {
return true
}
if f.SomeInThreadHaveKeyword != "" {
return true
}
if f.Subject != "" {
return true
}
if f.Text != "" {
return true
}
if f.To != "" {
return true
}
return false
}
var _ EmailFilterElement = &EmailFilterCondition{}
type EmailFilterOperator struct {
Operator FilterOperatorTerm `json:"operator"`
Conditions []EmailFilterElement `json:"conditions,omitempty"`
}
func (o EmailFilterOperator) _isAnEmailFilterElement() {
}
func (o EmailFilterOperator) IsNotEmpty() bool {
return len(o.Conditions) > 0
}
var _ EmailFilterElement = &EmailFilterOperator{}
type EmailComparator struct {
// The name of the property on the objects to compare.
Property string `json:"property,omitempty"`
// If true, sort in ascending order.
//
// Optional; default value: true.
//
// If false, reverse the comparators results to sort in descending order.
IsAscending bool `json:"isAscending,omitempty"`
// The identifier, as registered in the collation registry defined in [RFC4790],
// for the algorithm to use when comparing the order of strings.
//
// Optional; default is server dependent.
//
// The algorithms the server supports are advertised in the capabilities object returned
// with the Session object.
//
// [RFC4790]: https://www.rfc-editor.org/rfc/rfc4790.html
Collation string `json:"collation,omitempty"`
// Email-specific: keyword that must be included in the Email object.
Keyword string `json:"keyword,omitempty"`
}
// If an anchor argument is given, the anchor is looked for in the results after filtering
// and sorting.
//
// If found, the anchorOffset is then added to its index. If the resulting index is now negative,
// it is clamped to 0. This index is now used exactly as though it were supplied as the position
// argument. If the anchor is not found, the call is rejected with an anchorNotFound error.
//
// If an anchor is specified, any position argument supplied by the client MUST be ignored.
// If no anchor is supplied, any anchorOffset argument MUST be ignored.
//
// A client can use anchor instead of position to find the index of an id within a large set of results.
type EmailQueryCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// Determines the set of Emails returned in the results.
//
// If null, all objects in the account of this type are included in the results.
Filter EmailFilterElement `json:"filter,omitempty"`
// Lists the names of properties to compare between two Email records, and how to compare
// them, to determine which comes first in the sort.
//
// If two Email records have an identical value for the first comparator, the next comparator
// will be considered, and so on. If all comparators are the same (this includes the case
// where an empty array or null is given as the sort argument), the sort order is server
// dependent, but it MUST be stable between calls to Email/query.
Sort []EmailComparator `json:"sort,omitempty"`
// If true, Emails in the same Thread as a previous Email in the list (given the
// filter and sort order) will be removed from the list.
//
// This means only one Email at most will be included in the list for any given Thread.
CollapseThreads bool `json:"collapseThreads,omitempty"`
// The zero-based index of the first id in the full list of results to return.
//
// If a negative value is given, it is an offset from the end of the list.
// Specifically, the negative value MUST be added to the total number of results given
// the filter, and if still negative, its clamped to 0. This is now the zero-based
// index of the first id to return.
//
// If the index is greater than or equal to the total number of objects in the results
// list, then the ids array in the response will be empty, but this is not an error.
Position int `json:"position,omitempty"`
// An Email id.
//
// If supplied, the position argument is ignored.
// The index of this id in the results will be used in combination with the anchorOffset
// argument to determine the index of the first result to return.
Anchor string `json:"anchor,omitempty"`
// The index of the first result to return relative to the index of the anchor,
// if an anchor is given.
//
// Default: 0.
//
// This MAY be negative.
//
// For example, -1 means the Email immediately preceding the anchor is the first result in
// the list returned.
AnchorOffset int `json:"anchorOffset,omitzero"`
// The maximum number of results to return.
//
// If null, no limit presumed.
// The server MAY choose to enforce a maximum limit argument.
// In this case, if a greater value is given (or if it is null), the limit is clamped
// to the maximum; the new limit is returned with the response so the client is aware.
//
// If a negative value is given, the call MUST be rejected with an invalidArguments error.
Limit *uint `json:"limit,omitempty"`
// Does the client wish to know the total number of results in the query?
//
// This may be slow and expensive for servers to calculate, particularly with complex filters,
// so clients should take care to only request the total when needed.
CalculateTotal bool `json:"calculateTotal,omitempty"`
}
type EmailGetCommand struct {
// The ids of the Email objects to return.
//
// If null, then all records of the data type are returned, if this is supported for that
// data type and the number of records does not exceed the maxObjectsInGet limit.
Ids []string `json:"ids,omitempty"`
// The id of the account to use.
AccountId string `json:"accountId"`
// If supplied, only the properties listed in the array are returned for each Email object.
//
// If null, the following properties are returned:
//
// [ "id", "blobId", "threadId", "mailboxIds", "keywords", "size",
// "receivedAt", "messageId", "inReplyTo", "references", "sender", "from",
// "to", "cc", "bcc", "replyTo", "subject", "sentAt", "hasAttachment",
// "preview", "bodyValues", "textBody", "htmlBody", "attachments" ]
//
// The id property of the object is always returned, even if not explicitly requested.
//
// If an invalid property is requested, the call MUST be rejected with an invalidArguments error.
Properties []string `json:"properties,omitempty"`
// A list of properties to fetch for each EmailBodyPart returned.
//
// If omitted, this defaults to:
//
// [ "partId", "blobId", "size", "name", "type", "charset", "disposition", "cid", "language", "location" ]
//
BodyProperties []string `json:"bodyProperties,omitempty"`
// (default: false) If true, the bodyValues property includes any text/* part in the textBody property.
FetchTextBodyValues bool `json:"fetchTextBodyValues,omitzero"`
// (default: false) If true, the bodyValues property includes any text/* part in the htmlBody property.
FetchHTMLBodyValues bool `json:"fetchHTMLBodyValues,omitzero"`
// (default: false) If true, the bodyValues property includes any text/* part in the bodyStructure property.
FetchAllBodyValues bool `json:"fetchAllBodyValues,omitzero"`
// If greater than zero, the value property of any EmailBodyValue object returned in bodyValues
// MUST be truncated if necessary so it does not exceed this number of octets in size.
//
// If 0 (the default), no truncation occurs.
//
// The server MUST ensure the truncation results in valid UTF-8 and does not occur mid-codepoint.
//
// If the part is of type text/html, the server SHOULD NOT truncate inside an HTML tag, e.g., in
// the middle of <a href="https://example.com">.
//
// There is no requirement for the truncated form to be a balanced tree or valid HTML (indeed, the original
// source may well be neither of these things).
MaxBodyValueBytes uint `json:"maxBodyValueBytes,omitempty"`
}
// Reference to Previous Method Results
//
// To allow clients to make more efficient use of the network and avoid round trips, an argument to one method
// can be taken from the result of a previous method call in the same request.
//
// To do this, the client prefixes the argument name with # (an [octothorpe]).
//
// When processing a method call, the server MUST first check the arguments object for any names beginning with #.
//
// If found, the result reference should be resolved and the value used as the “real” argument.
//
// The method is then processed as normal.
//
// If any result reference fails to resolve, the whole method MUST be rejected with an invalidResultReference error.
//
// If an arguments object contains the same argument name in normal and referenced form (e.g., foo and #foo),
// the method MUST return an invalidArguments error.
//
// To resolve:
//
// 1. Find the first response with a method call id identical to the resultOf property of the ResultReference
// in the methodResponses array from previously processed method calls in the same request.
// If none, evaluation fails.
// 2. If the response name is not identical to the name property of the ResultReference, evaluation fails.
// 3. Apply the path to the arguments object of the response (the second item in the response array)
// following the JSON Pointer algorithm [RFC6901], except with the following addition in “Evaluation” (see Section 4):
// 4. If the currently referenced value is a JSON array, the reference token may be exactly the single character *,
// making the new referenced value the result of applying the rest of the JSON Pointer tokens to every item in the
// array and returning the results in the same order in a new array.
// 5. If the result of applying the rest of the pointer tokens to each item was itself an array, the contents of this
// array are added to the output rather than the array itself (i.e., the result is flattened from an array of
// arrays to a single array).
//
// [octothorpe]; https://en.wiktionary.org/wiki/octothorpe
// [RFC6901]: https://datatracker.ietf.org/doc/html/rfc6901
type ResultReference struct {
// The method call id of a previous method call in the current request.
ResultOf string `json:"resultOf"`
// The required name of a response to that method call.
Name Command `json:"name"`
// A pointer into the arguments of the response selected via the name and resultOf properties.
//
// This is a JSON Pointer [RFC6901], except it also allows the use of * to map through an array.
//
// [RFC6901]: https://datatracker.ietf.org/doc/html/rfc6901
Path string `json:"path,omitempty"`
}
type EmailGetRefCommand struct {
// The ids of the Email objects to return.
//
// If null, then all records of the data type are returned, if this is supported for that
// data type and the number of records does not exceed the maxObjectsInGet limit.
IdsRef *ResultReference `json:"#ids,omitempty"`
// The id of the account to use.
AccountId string `json:"accountId"`
// If supplied, only the properties listed in the array are returned for each Email object.
//
// If null, the following properties are returned:
//
// [ "id", "blobId", "threadId", "mailboxIds", "keywords", "size",
// "receivedAt", "messageId", "inReplyTo", "references", "sender", "from",
// "to", "cc", "bcc", "replyTo", "subject", "sentAt", "hasAttachment",
// "preview", "bodyValues", "textBody", "htmlBody", "attachments" ]
//
// The id property of the object is always returned, even if not explicitly requested.
//
// If an invalid property is requested, the call MUST be rejected with an invalidArguments error.
Properties []string `json:"properties,omitempty"`
// A list of properties to fetch for each EmailBodyPart returned.
//
// If omitted, this defaults to:
//
// [ "partId", "blobId", "size", "name", "type", "charset", "disposition", "cid", "language", "location" ]
//
BodyProperties []string `json:"bodyProperties,omitempty"`
// (default: false) If true, the bodyValues property includes any text/* part in the textBody property.
FetchTextBodyValues bool `json:"fetchTextBodyValues,omitzero"`
// (default: false) If true, the bodyValues property includes any text/* part in the htmlBody property.
FetchHTMLBodyValues bool `json:"fetchHTMLBodyValues,omitzero"`
// (default: false) If true, the bodyValues property includes any text/* part in the bodyStructure property.
FetchAllBodyValues bool `json:"fetchAllBodyValues,omitzero"`
// If greater than zero, the value property of any EmailBodyValue object returned in bodyValues
// MUST be truncated if necessary so it does not exceed this number of octets in size.
//
// If 0 (the default), no truncation occurs.
//
// The server MUST ensure the truncation results in valid UTF-8 and does not occur mid-codepoint.
//
// If the part is of type text/html, the server SHOULD NOT truncate inside an HTML tag, e.g., in
// the middle of <a href="https://example.com">.
//
// There is no requirement for the truncated form to be a balanced tree or valid HTML (indeed, the original
// source may well be neither of these things).
MaxBodyValueBytes uint `json:"maxBodyValueBytes,omitempty"`
}
type EmailChangesCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// The current state of the client.
//
// This is the string that was returned as the state argument in the Email/get response.
// The server will return the changes that have occurred since this state.
SinceState State `json:"sinceState,omitzero,omitempty"`
// The maximum number of ids to return in the response.
//
// The server MAY choose to return fewer than this value but MUST NOT return more.
// If not given by the client, the server may choose how many to return.
// If supplied by the client, the value MUST be a positive integer greater than 0.
MaxChanges uint `json:"maxChanges,omitzero"`
}
type EmailAddress struct {
// The display-name of the mailbox [RFC5322].
//
// If this is a quoted-string:
// 1. The surrounding DQUOTE characters are removed.
// 2. Any quoted-pair is decoded.
// 3. White space is unfolded, and then any leading and trailing white space is removed.
// If there is no display-name but there is a comment immediately following the addr-spec, the value of this
// SHOULD be used instead. Otherwise, this property is null.
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
//
// example: $emailAddressName
Name string `json:"name,omitempty"`
// The addr-spec of the mailbox [RFC5322].
//
// Any syntactically correct encoded sections [RFC2047] with a known encoding MUST be decoded,
// following the same rules as for the Text form.
//
// Parsing SHOULD be best effort in the face of invalid structure to accommodate invalid messages and
// semi-complete drafts. EmailAddress objects MAY have an email property that does not conform to the
// addr-spec form (for example, may not contain an @ symbol).
//
// [RFC2047]: https://www.rfc-editor.org/rfc/rfc2047.html
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
//
// example: $emailAddressEmail
Email string `json:"email,omitempty"`
}
type EmailAddressGroup struct {
// The display-name of the group [RFC5322], or null if the addresses are not part of a group.
//
// If this is a quoted-string, it is processed the same as the name in the EmailAddress type.
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
Name string `json:"name,omitempty"`
// The mailbox values that belong to this group, represented as EmailAddress objects.
Addresses []EmailAddress `json:"addresses,omitempty"`
}
type EmailHeader struct {
// The header field name as defined in [RFC5322], with the same capitalization that it has in the message.
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
Name string `json:"name"`
// The header field value as defined in [RFC5322], in Raw form.
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
Value string `json:"value"`
}
// Email body part.
//
// The client may specify a `partId` OR a `blobId`, but not both.
// If a `partId` is given, this `partId` MUST be present in the `bodyValues` property.
//
// The `charset` property MUST be omitted if a `partId` is given (the parts content is included
// in `bodyValues`, and the server may choose any appropriate encoding).
//
// The `size` property MUST be omitted if a `partId` is given. If a `blobId` is given, it may be
// included but is ignored by the server (the size is actually calculated from the blob content
// itself).
//
// A `Content-Transfer-Encoding` header field MUST NOT be given.
type EmailBodyPart struct {
// Identifies this part uniquely within the Email.
//
// This is scoped to the `emailId` and has no meaning outside of the JMAP Email object representation.
// This is null if, and only if, the part is of type `multipart/*`.
//
// example: $attachmentPartId
PartId string `json:"partId,omitempty"`
// The id representing the raw octets of the contents of the part, after decoding any known
// `Content-Transfer-Encoding` (as defined in [RFC2045]), or null if, and only if, the part is of type `multipart/*`.
//
// Note that two parts may be transfer-encoded differently but have the same blob id if their decoded octets are identical
// and the server is using a secure hash of the data for the blob id.
// If the transfer encoding is unknown, it is treated as though it had no transfer encoding.
//
// [RFC2045]: https://www.rfc-editor.org/rfc/rfc2045.html
//
// example: $blobId
BlobId string `json:"blobId,omitempty"`
// The size, in octets, of the raw data after content transfer decoding (as referenced by the `blobId`, i.e.,
// the number of octets in the file the user would download).
//
// example: 31219
Size int `json:"size,omitempty"`
// This is a list of all header fields in the part, in the order they appear in the message.
//
// The values are in Raw form.
Headers []EmailHeader `json:"headers,omitempty"`
// This is the decoded filename parameter of the `Content-Disposition` header field per [RFC2231], or
// (for compatibility with existing systems) if not present, then its the decoded name parameter of
// the `Content-Type` header field per [RFC2047].
//
// [RFC2231]: https://www.rfc-editor.org/rfc/rfc2231.html
// [RFC2047]: https://www.rfc-editor.org/rfc/rfc2047.html
//
// name: $attachmentName
Name string `json:"name,omitempty"`
// The value of the `Content-Type` header field of the part, if present; otherwise, the implicit type as per
// the MIME standard (`text/plain` or `message/rfc822` if inside a `multipart/digest`).
//
// [CFWS] is removed and any parameters are stripped.
//
// [CFWS]: https://www.rfc-editor.org/rfc/rfc5322#section-3.2.2
//
// example: $attachmentType
Type string `json:"type,omitempty"`
// The value of the `charset` parameter of the `Content-Type` header field, if present, or null if the header
// field is present but not of type `text/*`.
//
// If there is no `Content-Type` header field, or it exists and is of type `text/*` but has no `charset` parameter,
// this is the implicit charset as per the MIME standard: `us-ascii`.
//
// example: $attachmentCharset
Charset string `json:"charset,omitempty"`
// The value of the `Content-Disposition` header field of the part, if present;
// otherwise, its null.
//
// [CFWS] is removed and any parameters are stripped.
//
// [CFWS]: https://www.rfc-editor.org/rfc/rfc5322#section-3.2.2
//
// example: $attachmentDisposition
Disposition string `json:"disposition,omitempty"`
// The value of the `Content-Id` header field of the part, if present; otherwise its null.
//
// [CFWS] and surrounding angle brackets (`<>`) are removed.
//
// This may be used to reference the content from within a `text/html` body part HTML using the `cid:` protocol,
// as defined in [RFC2392].
//
// [RFC2392]: https://www.rfc-editor.org/rfc/rfc2392.html
// [CFWS]: https://www.rfc-editor.org/rfc/rfc5322#section-3.2.2
//
// example: $attachmentCid
Cid string `json:"cid,omitempty"`
// The list of language tags, as defined in [RFC3282], in the `Content-Language` header field of the part,
// if present.
//
// [RFC3282]: https://www.rfc-editor.org/rfc/rfc3282.html
Language string `json:"language,omitempty"`
// The URI, as defined in [RFC2557], in the `Content-Location` header field of the part, if present.
//
// [RFC2557]: https://www.rfc-editor.org/rfc/rfc2557.html
Location string `json:"location,omitempty"`
// If the type is `multipart/*`, this contains the body parts of each child.
SubParts []EmailBodyPart `json:"subParts,omitempty"`
}
type EmailBodyValue struct {
// The value of the body part after decoding `Content-Transfer-Encoding` and the `Content-Type` charset,
// if both known to the server, and with any CRLF replaced with a single LF.
//
// The server MAY use heuristics to determine the charset to use for decoding if the charset is unknown,
// no charset is given, or it believes the charset given is incorrect.
//
// Decoding is best effort; the server SHOULD insert the unicode replacement character (`U+FFFD`) and continue
// when a malformed section is encountered.
//
// Note that due to the charset decoding and line ending normalisation, the length of this string will
// probably not be exactly the same as the size property on the corresponding EmailBodyPart.
Value string `json:"value,omitempty"`
// This is true if malformed sections were found while decoding the charset,
// or the charset was unknown, or the content-transfer-encoding was unknown.
//
// Default value is false.
IsEncodingProblem bool `json:"isEncodingProblem,omitzero"`
// This is true if the value has been truncated.
//
// Default value is false.
IsTruncated bool `json:"isTruncated,omitzero"`
}
const (
EmailPropertyId = "id"
EmailPropertyBlodId = "blobId"
EmailPropertyThreadId = "threadId"
EmailPropertyMailboxIds = "mailboxIds"
EmailPropertyKeywords = "keywords"
EmailPropertySize = "size"
EmailPropertyReceivedAt = "receivedAt"
EmailPropertyHeaders = "headers"
EmailPropertyMessageId = "messageId"
EmailPropertyInReplyTo = "inReplyTo"
EmailPropertyReferences = "references"
EmailPropertySender = "sender"
EmailPropertyFrom = "from"
EmailPropertyTo = "to"
EmailPropertyCc = "cc"
EmailPropertyBcc = "bcc"
EmailPropertyReplyTo = "replyTo"
EmailPropertySubject = "subject"
EmailPropertySentAt = "sentAt"
EmailPropertyBodyStructure = "bodyStructure"
EmailPropertyBodyValues = "bodyValues"
EmailPropertyTextBody = "textBody"
EmailPropertyHtmlBody = "htmlBody"
EmailPropertyAttachments = "attachments"
EmailPropertyHasAttachment = "hasAttachment"
EmailPropertyPreview = "preview"
)
var EmailProperties = []string{
EmailPropertyId,
EmailPropertyBlodId,
EmailPropertyThreadId,
EmailPropertyMailboxIds,
EmailPropertyKeywords,
EmailPropertySize,
EmailPropertyReceivedAt,
EmailPropertyHeaders,
EmailPropertyMessageId,
EmailPropertyInReplyTo,
EmailPropertyReferences,
EmailPropertySender,
EmailPropertyFrom,
EmailPropertyTo,
EmailPropertyCc,
EmailPropertyBcc,
EmailPropertyReplyTo,
EmailPropertySubject,
EmailPropertySentAt,
EmailPropertyBodyStructure,
EmailPropertyBodyValues,
EmailPropertyTextBody,
EmailPropertyHtmlBody,
EmailPropertyAttachments,
EmailPropertyHasAttachment,
EmailPropertyPreview,
}
// An Email.
//
// swagger:model
type Email struct {
// The id of the Email object.
//
// Note that this is the JMAP object id, NOT the `Message-ID` header field value of the message [RFC5322].
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
//
// required: true
// example: $emailId
Id string `json:"id,omitempty"`
// The id representing the raw octets of the message [RFC5322] for this Email.
//
// This may be used to download the raw original message or to attach it directly to another Email, etc.
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
//
// example: $blobId
BlobId string `json:"blobId,omitempty"`
// The id of the Thread to which this Email belongs.
//
// example: $threadId
ThreadId string `json:"threadId,omitempty"`
// The number of emails (this one included) that are in the thread this email is in.
// Note that this is not part of the JMAP specification, and is only calculated when requested.
ThreadSize int `json:"threadSize,omitzero"`
// The account ID this email belongs to.
// Note that this is not part of the JMAP specification, and is only contained in all-account operations.
AccountId string `json:"accountId,omitempty"`
// The set of Mailbox ids this Email belongs to.
//
// An Email in the mail store MUST belong to one or more Mailboxes at all times (until it is destroyed).
// The set is represented as an object, with each key being a Mailbox id.
//
// The value for each key in the object MUST be true.
//
// example: {"a": true}
MailboxIds map[string]bool `json:"mailboxIds,omitempty"`
// A set of keywords that apply to the Email.
//
// The set is represented as an object, with the keys being the keywords.
//
// The value for each key in the object MUST be true.
//
// Keywords are shared with IMAP.
//
// The six system keywords from IMAP get special treatment.
//
// The following four keywords have their first character changed from \ in IMAP to $ in JMAP and have particular semantic meaning:
//
// - $draft: The Email is a draft the user is composing.
// - $seen: The Email has been read.
// - $flagged: The Email has been flagged for urgent/special attention.
// - $answered: The Email has been replied to.
//
// The IMAP \Recent keyword is not exposed via JMAP. The IMAP \Deleted keyword is also not present: IMAP uses a delete+expunge model,
// which JMAP does not. Any message with the \Deleted keyword MUST NOT be visible via JMAP (and so are not counted in the
// “totalEmails”, “unreadEmails”, “totalThreads”, and “unreadThreads” Mailbox properties).
//
// Users may add arbitrary keywords to an Email.
// For compatibility with IMAP, a keyword is a case-insensitive string of 1255 characters in the ASCII subset
// %x21%x7e (excludes control chars and space), and it MUST NOT include any of these characters:
//
// ( ) { ] % * " \
//
// Because JSON is case sensitive, servers MUST return keywords in lowercase.
//
// The [IMAP and JMAP Keywords] registry as established in [RFC5788] assigns semantic meaning to some other
// keywords in common use.
//
// New keywords may be established here in the future. In particular, note:
//
// - $forwarded: The Email has been forwarded.
// - $phishing: The Email is highly likely to be phishing.
// Clients SHOULD warn users to take care when viewing this Email and disable links and attachments.
// - $junk: The Email is definitely spam.
// Clients SHOULD set this flag when users report spam to help train automated spam-detection systems.
// - $notjunk: The Email is definitely not spam.
// Clients SHOULD set this flag when users indicate an Email is legitimate, to help train automated spam-detection systems.
//
// [IMAP and JMAP Keywords]: https://www.iana.org/assignments/imap-jmap-keywords/
// [RFC5788]: https://www.rfc-editor.org/rfc/rfc5788.html
Keywords map[string]bool `json:"keywords,omitempty"`
// The size, in octets, of the raw data for the message [RFC5322]
// (as referenced by the blobId, i.e., the number of octets in the file the user would download).
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
Size int `json:"size,omitzero"`
// The date the Email was received by the message store.
//
// This is the internal date in IMAP [RFC3501].
//
// [RFC3501]: https://www.rfc-editor.org/rfc/rfc3501.html
ReceivedAt time.Time `json:"receivedAt,omitzero"`
// This is a list of all header fields [RFC5322], in the same order they appear in the message.
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
Headers []EmailHeader `json:"headers,omitempty"`
// The value is identical to the value of header:Message-ID:asMessageIds.
//
// For messages conforming to [RFC5322] this will be an array with a single entry.
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
MessageId []string `json:"messageId,omitempty"`
// The value is identical to the value of header:In-Reply-To:asMessageIds.
InReplyTo []string `json:"inReplyTo,omitempty"`
// The value is identical to the value of header:References:asMessageIds.
References []string `json:"references,omitempty"`
// The value is identical to the value of header:Sender:asAddresses.
Sender []EmailAddress `json:"sender,omitempty"`
// The value is identical to the value of header:From:asAddresses.
From []EmailAddress `json:"from,omitempty"`
// The value is identical to the value of header:To:asAddresses.
To []EmailAddress `json:"to,omitempty"`
// The value is identical to the value of header:Cc:asAddresses.
Cc []EmailAddress `json:"cc,omitempty"`
// The value is identical to the value of header:Bcc:asAddresses.
Bcc []EmailAddress `json:"bcc,omitempty"`
// The value is identical to the value of header:Reply-To:asAddresses.
ReplyTo []EmailAddress `json:"replyTo,omitempty"`
// The value is identical to the value of header:Subject:asText.
Subject string `json:"subject,omitempty"`
// The value is identical to the value of header:Date:asDate.
SentAt time.Time `json:"sentAt,omitzero"`
// This is the full MIME structure of the message body, without recursing into message/rfc822 or message/global parts.
//
// Note that EmailBodyParts may have subParts if they are of type multipart/*.
BodyStructure *EmailBodyPart `json:"bodyStructure,omitzero"`
// This is a map of partId to an EmailBodyValue object for none, some, or all text/* parts.
//
// Which parts are included and whether the value is truncated is determined by various arguments to Email/get and Email/parse.
BodyValues map[string]EmailBodyValue `json:"bodyValues,omitempty"`
// A list of text/plain, text/html, image/*, audio/*, and/or video/* parts to display (sequentially) as the
// message body, with a preference for text/plain when alternative versions are available.
TextBody []EmailBodyPart `json:"textBody,omitempty"`
// A list of text/plain, text/html, image/*, audio/*, and/or video/* parts to display (sequentially) as the
// message body, with a preference for text/html when alternative versions are available.
HtmlBody []EmailBodyPart `json:"htmlBody,omitempty"`
// A list, traversing depth-first, of all parts in bodyStructure.
//
// They must satisfy either of the following conditions:
//
// - not of type multipart/* and not included in textBody or htmlBody
// - of type image/*, audio/*, or video/* and not in both textBody and htmlBody
//
// None of these parts include subParts, including message/* types.
//
// Attached messages may be fetched using the Email/parse method and the blobId.
//
// Note that a text/html body part HTML may reference image parts in attachments by using cid:
// links to reference the Content-Id, as defined in [RFC2392], or by referencing the Content-Location.
//
// [RFC2392]: https://www.rfc-editor.org/rfc/rfc2392.html
Attachments []EmailBodyPart `json:"attachments,omitempty"`
// This is true if there are one or more parts in the message that a client UI should offer as downloadable.
//
// A server SHOULD set hasAttachment to true if the attachments list contains at least one item that
// does not have Content-Disposition: inline.
//
// The server MAY ignore parts in this list that are processed automatically in some way or are referenced
// as embedded images in one of the text/html parts of the message.
//
// The server MAY set hasAttachment based on implementation-defined or site-configurable heuristics.
HasAttachment bool `json:"hasAttachment,omitempty"`
// A plaintext fragment of the message body.
//
// This is intended to be shown as a preview line when listing messages in the mail store and may be truncated
// when shown.
//
// The server may choose which part of the message to include in the preview; skipping quoted sections and
// salutations and collapsing white space can result in a more useful preview.
//
// This MUST NOT be more than 256 characters in length.
//
// As this is derived from the message content by the server, and the algorithm for doing so could change over
// time, fetching this for an Email a second time MAY return a different result.
// However, the previous value is not considered incorrect, and the change SHOULD NOT cause the Email object
// to be considered as changed by the server.
Preview string `json:"preview,omitempty"`
}
type AddressParameters struct {
HoldUntil time.Time `json:"HOLDUNTIL,omitzero"`
HoldForSeconds uint `json:"HOLDFOR,omitzero"`
}
type Address struct {
// The email address being represented by the object.
//
// This is a “Mailbox” as used in the Reverse-path or Forward-path of the MAIL FROM or RCPT TO command in [RFC5321].
//
// [RFC5321]: https://datatracker.ietf.org/doc/html/rfc5321
Email string `json:"email,omitempty"`
// Any parameters to send with the email address (either mail-parameter or rcpt-parameter as appropriate,
// as specified in [RFC5321]).
//
// If supplied, each key in the object is a parameter name, and the value is either the parameter value (type String)
// or null if the parameter does not take a value.
//
// [RFC5321]: https://datatracker.ietf.org/doc/html/rfc5321
Parameters *AddressParameters `json:"parameters,omitempty"`
}
// Information for use when sending via SMTP.
type Envelope struct {
// The email address to use as the return address in the SMTP submission,
// plus any parameters to pass with the MAIL FROM address.
MailFrom Address `json:"mailFrom"`
// The email addresses to send the message to, and any RCPT TO parameters to pass with the recipient.
RcptTo []Address `json:"rcptTo"`
}
type EmailSubmissionUndoStatus string
const (
// It may be possible to cancel this submission.
UndoStatusPending EmailSubmissionUndoStatus = "pending"
// The message has been relayed to at least one recipient in a manner that cannot be recalled.
// It is no longer possible to cancel this submission.
UndoStatusFinal EmailSubmissionUndoStatus = "final"
// The submission was canceled and will not be delivered to any recipient.
UndoStatusCanceled EmailSubmissionUndoStatus = "canceled"
)
type DeliveryStatusDelivered string
const (
// The message is in a local mail queue and status will change once it exits the local mail
// queues.
// The smtpReply property may still change.
DeliveredQueued DeliveryStatusDelivered = "queued"
// The message was successfully delivered to the mail store of the recipient.
// The smtpReply property is final.
DeliveredYes DeliveryStatusDelivered = "yes"
// Delivery to the recipient permanently failed.
// The smtpReply property is final.
DeliveredNo DeliveryStatusDelivered = "no"
// The final delivery status is unknown, (e.g., it was relayed to an external machine
// and no further information is available).
//
// The smtpReply property may still change if a DSN arrives.
DeliveredUnknown DeliveryStatusDelivered = "unknown"
)
type DeliveryStatusDisplayed string
const (
// The display status is unknown.
//
// This is the initial value.
DisplayedUnknown DeliveryStatusDisplayed = "unknown"
// The recipients system claims the message content has been displayed to the recipient.
//
// Note that there is no guarantee that the recipient has noticed, read, or understood the content.
DisplayedYes DeliveryStatusDisplayed = "yes"
)
type DeliveryStatus struct {
// The SMTP reply string returned for this recipient when the server last tried to
// relay the message, or in a later Delivery Status Notification (DSN, as defined in
// [RFC3464]) response for the message.
//
// This SHOULD be the response to the RCPT TO stage, unless this was accepted and the
// message as a whole was rejected at the end of the DATA stage, in which case the
// DATA stage reply SHOULD be used instead.
//
// [RFC3464]: https://datatracker.ietf.org/doc/html/rfc3464
SmtpReply string `json:"smtpReply"`
// Represents whether the message has been successfully delivered to the recipient.
//
// This MUST be one of the following values:
// - queued: The message is in a local mail queue and status will change once it exits
// the local mail queues. The smtpReply property may still change.
// - yes: The message was successfully delivered to the mail store of the recipient.
// The smtpReply property is final.
// - no: Delivery to the recipient permanently failed. The smtpReply property is final.
// - unknown: The final delivery status is unknown, (e.g., it was relayed to an external
// machine and no further information is available).
// The smtpReply property may still change if a DSN arrives.
Delivered DeliveryStatusDelivered `json:"delivered"`
// Represents whether the message has been displayed to the recipient.
//
// This MUST be one of the following values:
// - unknown: The display status is unknown. This is the initial value.
// - yes: The recipients system claims the message content has been displayed to the recipient.
// Note that there is no guarantee that the recipient has noticed, read, or understood the content.
Displayed DeliveryStatusDisplayed `json:"displayed"`
}
type EmailSubmission struct {
// The id of the EmailSubmission (server-set).
Id string `json:"id"`
// The id of the Identity to associate with this submission.
IdentityId string `json:"identityId"`
// The id of the Email to send.
//
// The Email being sent does not have to be a draft, for example, when “redirecting” an existing Email
// to a different address.
EmailId string `json:"emailId"`
// The Thread id of the Email to send (server-set).
//
// This is set by the server to the threadId property of the Email referenced by the emailId.
ThreadId string `json:"threadId"`
// Information for use when sending via SMTP.
//
// If the envelope property is null or omitted on creation, the server MUST generate this from the
// referenced Email as follows:
//
// - mailFrom: The email address in the Sender header field, if present; otherwise,
// its the email address in the From header field, if present.
// In either case, no parameters are added.
// - rcptTo: The deduplicated set of email addresses from the To, Cc, and Bcc header fields,
// if present, with no parameters for any of them.
Envelope *Envelope `json:"envelope,omitempty"`
// The date the submission was/will be released for delivery (server-set).
SendAt time.Time `json:"sendAt,omitzero"`
// This represents whether the submission may be canceled (server-set).
//
// This is server set on create and MUST be one of the following values:
//
// - pending: It may be possible to cancel this submission.
// - final: The message has been relayed to at least one recipient in a manner that cannot be
// recalled. It is no longer possible to cancel this submission.
// - canceled: The submission was canceled and will not be delivered to any recipient.
UndoStatus EmailSubmissionUndoStatus `json:"undoStatus"`
// This represents the delivery status for each of the submissions recipients, if known (server-set).
//
// This property MAY not be supported by all servers, in which case it will remain null.
//
// Servers that support it SHOULD update the EmailSubmission object each time the status of any of
// the recipients changes, even if some recipients are still being retried.
//
// This value is a map from the email address of each recipient to a DeliveryStatus object.
DeliveryStatus map[string]DeliveryStatus `json:"deliveryStatus"`
// A list of blob ids for DSNs [RFC3464] received for this submission,
// in order of receipt, oldest first (server-set) .
//
// The blob is the whole MIME message (with a top-level content-type of multipart/report), as received.
//
// [RFC3464]: https://datatracker.ietf.org/doc/html/rfc3464
DsnBlobIds []string `json:"dsnBlobIds,omitempty"`
// A list of blob ids for MDNs [RFC8098] received for this submission,
// in order of receipt, oldest first (server-set).
//
// The blob is the whole MIME message (with a top-level content-type of multipart/report), as received.
//
// [RFC8098]: https://datatracker.ietf.org/doc/html/rfc8098
MdnBlobIds []string `json:"mdnBlobIds,omitempty"`
}
type EmailSubmissionGetCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// The ids of the EmailSubmission objects to return.
//
// If null, then all records of the data type are returned, if this is supported for that data
// type and the number of records does not exceed the maxObjectsInGet limit.
Ids []string `json:"ids,omitempty"`
// If supplied, only the properties listed in the array are returned for each EmailSubmission object.
//
// If null, all properties of the object are returned. The id property of the object is always returned,
// even if not explicitly requested. If an invalid property is requested, the call MUST be rejected
// with an invalidArguments error.
Properties []string `json:"properties,omitempty"`
}
type EmailSubmissionGetRefCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// The ids of the EmailSubmission objects to return.
//
// If null, then all records of the data type are returned, if this is supported for that data
// type and the number of records does not exceed the maxObjectsInGet limit.
IdRef *ResultReference `json:"#ids,omitempty"`
// If supplied, only the properties listed in the array are returned for each EmailSubmission object.
//
// If null, all properties of the object are returned. The id property of the object is always returned,
// even if not explicitly requested. If an invalid property is requested, the call MUST be rejected
// with an invalidArguments error.
Properties []string `json:"properties,omitempty"`
}
type EmailSubmissionGetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A (preferably short) string representing the state on the server for all the data
// of this type in the account (not just the objects returned in this call).
//
// If the data changes, this string MUST change. If the EmailSubmission data is unchanged,
// servers SHOULD return the same state string on subsequent requests for this data type.
//
// When a client receives a response with a different state string to a previous call,
// it MUST either throw away all currently cached objects for the type or call
// EmailSubmission/changes to get the exact changes.
State State `json:"state"`
// An array of the EmailSubmission objects requested.
//
// This is the empty array if no objects were found or if the ids argument passed in
// was also an empty array.
//
// The results MAY be in a different order to the ids in the request arguments.
// If an identical id is included more than once in the request, the server MUST only
// include it once in either the list or the notFound argument of the response.
List []EmailSubmission `json:"list,omitempty"`
// This array contains the ids passed to the method for records that do not exist.
//
// The array is empty if all requested ids were found or if the ids argument passed in was
// either null or an empty array.
NotFound []string `json:"notFound,omitempty"`
}
// Patch Object.
//
// Example:
//
// - moves it from the drafts folder (which has Mailbox id “7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e”)
// to the sent folder (which we presume has Mailbox id “73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6”)
//
// - removes the $draft flag and
//
// {
// "mailboxIds/7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e": null,
// "mailboxIds/73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6": true,
// "keywords/$draft": null
// }
type PatchObject map[string]any
// same as EmailSubmission but without the server-set attributes
type EmailSubmissionCreate struct {
// The id of the Identity to associate with this submission.
IdentityId string `json:"identityId"`
// The id of the Email to send.
//
// The Email being sent does not have to be a draft, for example, when “redirecting” an existing
// Email to a different address.
EmailId string `json:"emailId"`
// Information for use when sending via SMTP.
Envelope *Envelope `json:"envelope,omitempty"`
}
type EmailSubmissionSetCommand struct {
AccountId string `json:"accountId"`
Create map[string]EmailSubmissionCreate `json:"create,omitempty"`
OldState State `json:"oldState,omitempty"`
NewState State `json:"newState,omitempty"`
// A map of EmailSubmission id to an object containing properties to update on the Email object
// referenced by the EmailSubmission if the create/update/destroy succeeds.
//
// (For references to EmailSubmissions created in the same “/set” invocation, this is equivalent
// to a creation-reference, so the id will be the creation id prefixed with a #.)
OnSuccessUpdateEmail map[string]PatchObject `json:"onSuccessUpdateEmail,omitempty"`
// A list of EmailSubmission ids for which the Email with the corresponding emailId should be destroyed
// if the create/update/destroy succeeds.
//
// (For references to EmailSubmission creations, this is equivalent to a creation-reference so the
// id will be the creation id prefixed with a #.)
OnSuccessDestroyEmail []string `json:"onSuccessDestroyEmail,omitempty"`
}
type CreatedEmailSubmission struct {
Id string `json:"id"`
}
type EmailSubmissionSetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// This is the sinceState argument echoed back; its the state from which the server is returning changes.
OldState State `json:"oldState"`
// This is the state the client will be in after applying the set of changes to the old state.
NewState State `json:"newState"`
// If true, the client may call EmailSubmission/changes again with the newState returned to get further
// updates.
//
// If false, newState is the current server state.
HasMoreChanges bool `json:"hasMoreChanges"`
// An array of ids for records that have been created since the old state.
Created map[string]CreatedEmailSubmission `json:"created,omitempty"`
// A map of the creation id to a SetError object for each record that failed to be created, or
// null if all successful.
NotCreated map[string]SetError `json:"notCreated,omitempty"`
// TODO(pbleser-oc) add updated and destroyed when they are needed
}
type Command string
type Invocation struct {
Command Command
Parameters any
Tag string
}
func invocation(command Command, parameters any, tag string) Invocation {
return Invocation{
Command: command,
Parameters: parameters,
Tag: tag,
}
}
type TypeOfRequest string
const RequestType = TypeOfRequest("Request")
type Request struct {
// The set of capabilities the client wishes to use.
//
// The client MAY include capability identifiers even if the method calls it makes do not utilise those capabilities.
// The server advertises the set of specifications it supports in the Session object (see [Section 2]), as keys on
// the capabilities property.
//
// [Section 2]: https://jmap.io/spec-core.html#the-jmap-session-resource
Using []string `json:"using"`
// An array of method calls to process on the server.
//
// The method calls MUST be processed sequentially, in order.
MethodCalls []Invocation `json:"methodCalls"`
// A map of a (client-specified) creation id to the id the server assigned when a record was successfully created (optional).
CreatedIds map[string]string `json:"createdIds,omitempty"`
// This MUST be the string "Request".
// The specification extends the Response object with two additional arguments when used over a WebSocket.
Type TypeOfRequest `json:"@type,omitempty"`
// A client-specified identifier for the request to be echoed back in the response to this request (optional).
Id string `json:"id,omitempty"`
}
type TypeOfResponse string
const ResponseType = TypeOfResponse("Response")
type Response struct {
// An array of responses, in the same format as the methodCalls on the Request object.
// The output of the methods MUST be added to the methodResponses array in the same order that the methods are processed.
MethodResponses []Invocation `json:"methodResponses"`
// A map of a (client-specified) creation id to the id the server assigned when a record was successfully created.
//
// Optional; only returned if given in the request.
//
// This MUST include all creation ids passed in the original createdIds parameter of the Request object, as well as any
// additional ones added for newly created records.
CreatedIds map[string]string `json:"createdIds,omitempty"`
// The current value of the “state” string on the Session object, as described in [Section 2].
// Clients may use this to detect if this object has changed and needs to be refetched.
//
// [Section 2]: https://jmap.io/spec-core.html#the-jmap-session-resource
SessionState SessionState `json:"sessionState"`
// This MUST be the string "Response".
// The specification extends the Response object with two additional arguments when used over a WebSocket.
Type TypeOfResponse `json:"@type,omitempty"`
// MUST be returned if an identifier is included in the request (optional).
RequestId string `json:"requestId,omitempty"`
}
type EmailQueryResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A string encoding the current state of the query on the server.
//
// This string MUST change if the results of the query (i.e., the matching ids and their sort order) have changed.
// The queryState string MAY change if something has changed on the server, which means the results may have changed
// but the server doesnt know for sure.
//
// The queryState string only represents the ordered list of ids that match the particular query (including its sort/filter).
// There is no requirement for it to change if a property on an object matching the query changes but the query results are unaffected
// (indeed, it is more efficient if the queryState string does not change in this case).
//
// The queryState string only has meaning when compared to future responses to a query with the same type/sort/filter or when used with
// /queryChanges to fetch changes.
//
// Should a client receive back a response with a different queryState string to a previous call, it MUST either throw away the currently
// cached query and fetch it again (note, this does not require fetching the records again, just the list of ids) or call
// Email/queryChanges to get the difference.
QueryState State `json:"queryState"`
// This is true if the server supports calling Email/queryChanges with these filter/sort parameters.
//
// Note, this does not guarantee that the Email/queryChanges call will succeed, as it may only be possible for a limited time
// afterwards due to server internal implementation details.
CanCalculateChanges bool `json:"canCalculateChanges"`
// The zero-based index of the first result in the ids array within the complete list of query results.
Position uint `json:"position"`
// The list of ids for each Email in the query results, starting at the index given by the position argument of this
// response and continuing until it hits the end of the results or reaches the limit number of ids.
//
// If position is >= total, this MUST be the empty list.
Ids []string `json:"ids"`
// The total number of Emails in the results (given the filter).
//
// Only if requested.
//
// This argument MUST be omitted if the calculateTotal request argument is not true.
Total uint `json:"total,omitempty,omitzero"`
// The limit enforced by the server on the maximum number of results to return (if set by the server).
//
// This is only returned if the server set a limit or used a different limit than that given in the request.
Limit uint `json:"limit,omitempty,omitzero"`
}
type EmailGetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A (preferably short) string representing the state on the server for all the data of this type
// in the account (not just the objects returned in this call).
//
// If the data changes, this string MUST change.
// If the Email data is unchanged, servers SHOULD return the same state string on subsequent requests for this data type.
State State `json:"state"`
// An array of the Email objects requested.
//
// This is the empty array if no objects were found or if the ids argument passed in was also an empty array.
//
// The results MAY be in a different order to the ids in the request arguments.
//
// If an identical id is included more than once in the request, the server MUST only include it once in either
// the list or the notFound argument of the response.
List []Email `json:"list"`
// This array contains the ids passed to the method for records that do not exist.
//
// The array is empty if all requested ids were found or if the ids argument passed in was either null or an empty array.
NotFound []string `json:"notFound"`
}
type EmailChangesResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// This is the sinceState argument echoed back; its the state from which the server is returning changes.
OldState State `json:"oldState"`
// This is the state the client will be in after applying the set of changes to the old state.
NewState State `json:"newState"`
// If true, the client may call Email/changes again with the newState returned to get further updates.
// If false, newState is the current server state.
HasMoreChanges bool `json:"hasMoreChanges"`
// An array of ids for records that have been created since the old state.
Created []string `json:"created,omitempty"`
// An array of ids for records that have been updated since the old state.
Updated []string `json:"updated,omitempty"`
// An array of ids for records that have been destroyed since the old state.
Destroyed []string `json:"destroyed,omitempty"`
}
type MailboxGetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A (preferably short) string representing the state on the server for all the data of this type in the account
// (not just the objects returned in this call).
// If the data changes, this string MUST change.
// If the Mailbox data is unchanged, servers SHOULD return the same state string on subsequent requests for this data type.
// When a client receives a response with a different state string to a previous call, it MUST either throw away all currently
// cached objects for the type or call Foo/changes to get the exact changes.
State State `json:"state"`
// An array of the Mailbox objects requested.
// This is the empty array if no objects were found or if the ids argument passed in was also an empty array.
// The results MAY be in a different order to the ids in the request arguments.
// If an identical id is included more than once in the request, the server MUST only include it once in either
// the list or the notFound argument of the response.
List []Mailbox `json:"list"`
// This array contains the ids passed to the method for records that do not exist.
// The array is empty if all requested ids were found or if the ids argument passed in was either null or an empty array.
NotFound []any `json:"notFound"`
}
type MailboxChangesResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// This is the sinceState argument echoed back; its the state from which the server is returning changes.
OldState State `json:"oldState"`
// This is the state the client will be in after applying the set of changes to the old state.
NewState State `json:"newState"`
// If true, the client may call Mailbox/changes again with the newState returned to get further updates.
//
// If false, newState is the current server state.
HasMoreChanges bool `json:"hasMoreChanges"`
// An array of ids for records that have been created since the old state.
Created []string `json:"created,omitempty"`
// An array of ids for records that have been updated since the old state.
Updated []string `json:"updated,omitempty"`
// An array of ids for records that have been destroyed since the old state.
Destroyed []string `json:"destroyed,omitempty"`
// If only the “totalEmails”, “unreadEmails”, “totalThreads”, and/or “unreadThreads” Mailbox properties have
// changed since the old state, this will be the list of properties that may have changed.
//
// If the server is unable to tell if only counts have changed, it MUST just be null.
UpdatedProperties []string `json:"updatedProperties,omitempty"`
}
type MailboxQueryResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A string encoding the current state of the query on the server.
//
// This string MUST change if the results of the query (i.e., the matching ids and their sort order) have changed.
// The queryState string MAY change if something has changed on the server, which means the results may have
// changed but the server doesnt know for sure.
//
// The queryState string only represents the ordered list of ids that match the particular query (including its
// sort/filter). There is no requirement for it to change if a property on an object matching the query changes
// but the query results are unaffected (indeed, it is more efficient if the queryState string does not change
// in this case). The queryState string only has meaning when compared to future responses to a query with the
// same type/sort/filter or when used with /queryChanges to fetch changes.
//
// Should a client receive back a response with a different queryState string to a previous call, it MUST either
// throw away the currently cached query and fetch it again (note, this does not require fetching the records
// again, just the list of ids) or call Mailbox/queryChanges to get the difference.
QueryState State `json:"queryState"`
// This is true if the server supports calling Mailbox/queryChanges with these filter/sort parameters.
//
// Note, this does not guarantee that the Mailbox/queryChanges call will succeed, as it may only be possible for
// a limited time afterwards due to server internal implementation details.
CanCalculateChanges bool `json:"canCalculateChanges"`
// The zero-based index of the first result in the ids array within the complete list of query results.
Position int `json:"position"`
// The list of ids for each Mailbox in the query results, starting at the index given by the position argument
// of this response and continuing until it hits the end of the results or reaches the limit number of ids.
//
// If position is >= total, this MUST be the empty list.
Ids []string `json:"ids"`
// The total number of Mailbox in the results (given the filter) (only if requested).
//
// This argument MUST be omitted if the calculateTotal request argument is not true.
Total int `json:"total,omitzero"`
// The limit enforced by the server on the maximum number of results to return (if set by the server).
//
// This is only returned if the server set a limit or used a different limit than that given in the request.
Limit int `json:"limit,omitzero"`
}
type EmailCreate struct {
// The set of Mailbox ids this Email belongs to.
//
// An Email in the mail store MUST belong to one or more Mailboxes at all times
// (until it is destroyed).
//
// The set is represented as an object, with each key being a Mailbox id.
// The value for each key in the object MUST be true.
MailboxIds map[string]bool `json:"mailboxIds,omitempty"`
// A set of keywords that apply to the Email.
//
// The set is represented as an object, with the keys being the keywords.
// The value for each key in the object MUST be true.
Keywords map[string]bool `json:"keywords,omitempty"`
// This is a list of all header fields [RFC5322], in the same order they appear in the message.
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
Headers []EmailHeader `json:"headers,omitempty"`
// The value is identical to the value of header:In-Reply-To:asMessageIds.
InReplyTo []string `json:"inReplyTo,omitempty"`
// The value is identical to the value of header:References:asMessageIds.
References []string `json:"references,omitempty"`
// The value is identical to the value of header:Sender:asAddresses.
Sender []EmailAddress `json:"sender,omitempty"`
// The ["From:" field] specifies the author(s) of the message, that is, the mailbox(es)
// of the person(s) or system(s) responsible for the writing of the message
//
// ["From:" field]: https://www.rfc-editor.org/rfc/rfc5322.html#section-3.6.2
From []EmailAddress `json:"from,omitempty"`
// The value is identical to the value of header:To:asAddresses.
To []EmailAddress `json:"to,omitempty"`
// The value is identical to the value of header:Cc:asAddresses.
Cc []EmailAddress `json:"cc,omitempty"`
// The value is identical to the value of header:Bcc:asAddresses.
Bcc []EmailAddress `json:"bcc,omitempty"`
// The value is identical to the value of header:Reply-To:asAddresses.
ReplyTo []EmailAddress `json:"replyTo,omitempty"`
// The "Subject:" field contains a short string identifying the topic of the message.
Subject string `json:"subject,omitempty"`
// The date the Email was received by the message store.
//
// (default: time of most recent Received header, or time of import on server if none).
ReceivedAt time.Time `json:"receivedAt,omitzero"`
// The origination date specifies the date and time at which the creator of the message indicated that
// the message was complete and ready to enter the mail delivery system.
//
// For instance, this might be the time that a user pushes the "send" or "submit" button in an
// application program.
//
// In any case, it is specifically not intended to convey the time that the message is actually transported,
// but rather the time at which the human or other creator of the message has put the message into its final
// form, ready for transport.
//
// (For example, a portable computer user who is not connected to a network might queue a message for delivery.
// The origination date is intended to contain the date and time that the user queued the message, not the time
// when the user connected to the network to send the message.)
SentAt time.Time `json:"sentAt,omitzero"`
// This is the full MIME structure of the message body, without recursing into message/rfc822 or message/global parts.
//
// Note that EmailBodyParts may have subParts if they are of type multipart/*.
BodyStructure *EmailBodyPart `json:"bodyStructure,omitempty"`
// This is a map of partId to an EmailBodyValue object for none, some, or all text/* parts.
BodyValues map[string]EmailBodyValue `json:"bodyValues,omitempty"`
// A list of text/plain, text/html, image/*, audio/*, and/or video/* parts to display (sequentially) as the
// message body, with a preference for text/plain when alternative versions are available.
TextBody []EmailBodyPart `json:"textBody,omitempty"`
// A list of text/plain, text/html, image/*, audio/*, and/or video/* parts to display (sequentially) as the
// message body, with a preference for text/html when alternative versions are available.
HtmlBody []EmailBodyPart `json:"htmlBody,omitempty"`
// A list, traversing depth-first, of all parts in bodyStructure.
//
// They must satisfy either of the following conditions:
//
// - not of type multipart/* and not included in textBody or htmlBody
// - of type image/*, audio/*, or video/* and not in both textBody and htmlBody
//
// None of these parts include subParts, including message/* types.
//
// Attached messages may be fetched using the Email/parse method and the blobId.
//
// Note that a text/html body part HTML may reference image parts in attachments by using cid:
// links to reference the Content-Id, as defined in [RFC2392], or by referencing the Content-Location.
//
// [RFC2392]: https://www.rfc-editor.org/rfc/rfc2392.html
Attachments []EmailBodyPart `json:"attachments,omitempty"`
}
type EmailUpdate map[string]any
type EmailSetCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// This is a state string as returned by the `Email/get` method.
//
// If supplied, the string must match the current state; otherwise, the method will be aborted and a
// `stateMismatch` error returned.
//
// If null, any changes will be applied to the current state.
IfInState string `json:"ifInState,omitempty"`
// A map of a creation id (a temporary id set by the client) to Email objects,
// or null if no objects are to be created.
//
// The Email object type definition may define default values for properties.
//
// Any such property may be omitted by the client.
//
// The client MUST omit any properties that may only be set by the server.
Create map[string]EmailCreate `json:"create,omitempty"`
// A map of an id to a `Patch` object to apply to the current Email object with that id,
// or null if no objects are to be updated.
//
// A `PatchObject` is of type `String[*]` and represents an unordered set of patches.
//
// The keys are a path in JSON Pointer Format [@!RFC6901], with an implicit leading `/` (i.e., prefix each key
// with `/` before applying the JSON Pointer evaluation algorithm).
//
// All paths MUST also conform to the following restrictions; if there is any violation, the update
// MUST be rejected with an `invalidPatch` error:
// !- The pointer MUST NOT reference inside an array (i.e., you MUST NOT insert/delete from an array; the array MUST be replaced in its entirety instead).
// !- All parts prior to the last (i.e., the value after the final slash) MUST already exist on the object being patched.
// !- There MUST NOT be two patches in the `PatchObject` where the pointer of one is the prefix of the pointer of the other, e.g., `"alerts/1/offset"` and `"alerts"`.
//
// The value associated with each pointer determines how to apply that patch:
// !- If null, set to the default value if specified for this property; otherwise, remove the property from the patched object. If the key is not present in the parent, this a no-op.
// !- Anything else: The value to set for this property (this may be a replacement or addition to the object being patched).
//
// Any server-set properties MAY be included in the patch if their value is identical to the current server value
// (before applying the patches to the object). Otherwise, the update MUST be rejected with an `invalidProperties` `SetError`.
//
// This patch definition is designed such that an entire Email object is also a valid `PatchObject`.
//
// The client may choose to optimise network usage by just sending the diff or may send the whole object; the server
// processes it the same either way.
Update map[string]EmailUpdate `json:"update,omitempty"`
// A list of ids for Email objects to permanently delete, or null if no objects are to be destroyed.
Destroy []string `json:"destroy,omitempty"`
}
type EmailSetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// The state string that would have been returned by Email/get before making the
// requested changes, or null if the server doesnt know what the previous state
// string was.
OldState State `json:"oldState,omitempty"`
// The state string that will now be returned by Email/get.
NewState State `json:"newState"`
// A map of the creation id to an object containing any properties of the created Email object
// that were not sent by the client.
//
// This includes all server-set properties (such as the id in most object types) and any properties
// that were omitted by the client and thus set to a default by the server.
//
// This argument is null if no Email objects were successfully created.
Created map[string]*Email `json:"created,omitempty"`
// The keys in this map are the ids of all Emails that were successfully updated.
//
// The value for each id is an Email object containing any property that changed in a way not
// explicitly requested by the PatchObject sent to the server, or null if none.
//
// This lets the client know of any changes to server-set or computed properties.
//
// This argument is null if no Email objects were successfully updated.
Updated map[string]*Email `json:"updated,omitempty"`
// A list of Email ids for records that were successfully destroyed, or null if none.
Destroyed []string `json:"destroyed,omitempty"`
// A map of the creation id to a SetError object for each record that failed to be created,
// or null if all successful.
NotCreated map[string]SetError `json:"notCreated,omitempty"`
// A map of the Email id to a SetError object for each record that failed to be updated,
// or null if all successful.
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
// A map of the Email id to a SetError object for each record that failed to be destroyed,
// or null if all successful.
NotDestroyed map[string]SetError `json:"notDestroyed,omitempty"`
}
const (
EmailMimeType = "message/rfc822"
)
type EmailImport struct {
// The id of the blob containing the raw message [RFC5322].
//
// [RFC5322]: https://www.rfc-editor.org/rfc/rfc5322.html
BlobId string `json:"blobId"`
// The ids of the Mailboxes to assign this Email to.
//
// At least one Mailbox MUST be given.
MailboxIds map[string]bool `json:"mailboxIds"`
// The keywords to apply to the Email.
Keywords map[string]bool `json:"keywords"`
// (default: time of most recent Received header, or time of import
// on server if none) The receivedAt date to set on the Email.
ReceivedAt time.Time `json:"receivedAt"`
}
type EmailImportCommand struct {
AccountId string `json:"accountId"`
// This is a state string as returned by the Email/get method.
//
// If supplied, the string must match the current state of the account referenced
// by the accountId; otherwise, the method will be aborted and a stateMismatch
// error returned.
//
// If null, any changes will be applied to the current state.
IfInState string `json:"ifInState,omitempty"`
// A map of creation id (client specified) to EmailImport objects.
Emails map[string]EmailImport `json:"emails"`
}
// Successfully imported Email.
type ImportedEmail struct {
// Id of the successfully imported Email.
Id string `json:"id"`
// Blob id of the successfully imported Email.
BlobId string `json:"blobId"`
// Thread id of the successfully imported Email.
ThreadId string `json:"threadId"`
// Size of the successfully imported Email.
Size int `json:"size"`
}
type EmailImportResponse struct {
// The id of the account used for this call.
AccountId string `json:"accountId"`
// The state string that would have been returned by Email/get on this account
// before making the requested changes, or null if the server doesnt know
// what the previous state string was.
OldState State `json:"oldState"`
// The state string that will now be returned by Email/get on this account.
NewState State `json:"newState"`
// A map of the creation id to an object containing the id, blobId, threadId,
// and size properties for each successfully imported Email, or null if none.
Created map[string]ImportedEmail `json:"created"`
// A map of the creation id to a SetError object for each Email that failed to
// be created, or null if all successful.
NotCreated map[string]SetError `json:"notCreated"`
}
// Replies are grouped together with the original message to form a Thread.
//
// In JMAP, a Thread is simply a flat list of Emails, ordered by date.
//
// Every Email MUST belong to a Thread, even if it is the only Email in the Thread.
type Thread struct {
// The id of the Thread.
Id string
// The ids of the Emails in the Thread, sorted by the receivedAt date of the Email,
// oldest first.
//
// If two Emails have an identical date, the sort is server dependent but MUST be
// stable (sorting by id is recommended).
EmailIds []string
}
type ThreadGetCommand struct {
AccountId string `json:"accountId"`
Ids []string `json:"ids,omitempty"`
}
type ThreadGetRefCommand struct {
AccountId string `json:"accountId"`
IdsRef *ResultReference `json:"#ids,omitempty"`
}
type ThreadGetResponse struct {
AccountId string
State State
List []Thread
NotFound []any
}
type IdentityGetCommand struct {
AccountId string `json:"accountId"`
Ids []string `json:"ids,omitempty"`
}
type IdentitySetCommand struct {
AccountId string `json:"accountId"`
IfInState string `json:"ifInState,omitempty"`
Create map[string]Identity `json:"create,omitempty"`
Update map[string]PatchObject `json:"update,omitempty"`
Destroy []string `json:"destroy,omitempty"`
}
type IdentitySetResponse struct {
AccountId string `json:"accountId"`
OldState State `json:"oldState,omitempty"`
NewState State `json:"newState,omitempty"`
Created map[string]Identity `json:"created,omitempty"`
Updated map[string]Identity `json:"updated,omitempty"`
Destroyed []string `json:"destroyed,omitempty"`
NotCreated map[string]SetError `json:"notCreated,omitempty"`
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
NotDestroyed map[string]SetError `json:"notDestroyed,omitempty"`
}
type Identity struct {
// The id of the Identity.
Id string `json:"id,omitempty"`
// The “From” name the client SHOULD use when creating a new Email from this Identity.
Name string `json:"name,omitempty"`
// The “From” email address the client MUST use when creating a new Email from this Identity.
//
// If the mailbox part of the address (the section before the “@”) is the single character
// * (e.g., *@example.com) then the client may use any valid address ending in that domain
// (e.g., foo@example.com).
Email string `json:"email,omitempty"`
// The Reply-To value the client SHOULD set when creating a new Email from this Identity.
ReplyTo string `json:"replyTo,omitempty"`
// The Bcc value the client SHOULD set when creating a new Email from this Identity.
Bcc *[]EmailAddress `json:"bcc,omitempty"`
// A signature the client SHOULD insert into new plaintext messages that will be sent from
// this Identity.
//
// Clients MAY ignore this and/or combine this with a client-specific signature preference.
TextSignature *string `json:"textSignature,omitempty"`
// A signature the client SHOULD insert into new HTML messages that will be sent from this
// Identity.
//
// This text MUST be an HTML snippet to be inserted into the <body></body> section of the HTML.
//
// Clients MAY ignore this and/or combine this with a client-specific signature preference.
HtmlSignature *string `json:"htmlSignature,omitempty"`
// Is the user allowed to delete this Identity?
//
// Servers may wish to set this to false for the users username or other default address.
//
// Attempts to destroy an Identity with mayDelete: false will be rejected with a standard
// forbidden SetError.
MayDelete bool `json:"mayDelete,omitzero"`
}
func (i Identity) AsPatch() PatchObject {
p := PatchObject{}
if i.Name != "" {
p["name"] = i.Name
}
if i.Email != "" {
p["email"] = i.Email
}
if i.ReplyTo != "" {
p["replyTo"] = i.ReplyTo
}
if i.Bcc != nil {
p["bcc"] = i.Bcc
}
if i.TextSignature != nil {
p["textSignature"] = i.TextSignature
}
if i.HtmlSignature != nil {
p["htmlSignature"] = i.HtmlSignature
}
return p
}
type IdentityGetResponse struct {
AccountId string `json:"accountId"`
State State `json:"state"`
List []Identity `json:"list,omitempty"`
NotFound []string `json:"notFound,omitempty"`
}
type VacationResponseGetCommand struct {
AccountId string `json:"accountId"`
}
// Vacation Response
//
// A vacation response sends an automatic reply when a message is delivered to the mail store,
// informing the original sender that their message may not be read for some time.
//
// Automated message sending can produce undesirable behaviour.
// To avoid this, implementors MUST follow the recommendations set forth in [RFC3834].
//
// The VacationResponse object represents the state of vacation-response-related settings for an account.
//
// [RFC3834]: https://www.rfc-editor.org/rfc/rfc3834.html
type VacationResponse struct {
// The id of the object.
// There is only ever one VacationResponse object, and its id is "singleton"
Id string `json:"id,omitempty"`
// Should a vacation response be sent if a message arrives between the "fromDate" and "toDate"?
IsEnabled bool `json:"isEnabled"`
// If "isEnabled" is true, messages that arrive on or after this date-time (but before the "toDate" if defined) should receive the
// user's vacation response. If null, the vacation response is effective immediately.
FromDate time.Time `json:"fromDate,omitzero"`
// If "isEnabled" is true, messages that arrive before this date-time but on or after the "fromDate" if defined) should receive the
// user's vacation response. If null, the vacation response is effective indefinitely.
ToDate time.Time `json:"toDate,omitzero"`
// The subject that will be used by the message sent in response to messages when the vacation response is enabled.
// If null, an appropriate subject SHOULD be set by the server.
Subject string `json:"subject,omitempty"`
// The plaintext body to send in response to messages when the vacation response is enabled.
// If this is null, the server SHOULD generate a plaintext body part from the "htmlBody" when sending vacation responses
// but MAY choose to send the response as HTML only. If both "textBody" and "htmlBody" are null, an appropriate default
// body SHOULD be generated for responses by the server.
TextBody string `json:"textBody,omitempty"`
// The HTML body to send in response to messages when the vacation response is enabled.
// If this is null, the server MAY choose to generate an HTML body part from the "textBody" when sending vacation responses
// or MAY choose to send the response as plaintext only.
HtmlBody string `json:"htmlBody,omitempty"`
}
type VacationResponseGetResponse struct {
// The identifier of the account this response pertains to.
AccountId string `json:"accountId"`
// A string representing the state on the server for all the data of this type in the account
// (not just the objects returned in this call).
//
// If the data changes, this string MUST change. If the data is unchanged, servers SHOULD return the same state string
// on subsequent requests for this data type.
State State `json:"state,omitempty"`
// An array of VacationResponse objects.
List []VacationResponse `json:"list,omitempty"`
// Contains identifiers of requested objects that were not found.
NotFound []any `json:"notFound,omitempty"`
}
type VacationResponseSetCommand struct {
AccountId string `json:"accountId"`
IfInState string `json:"ifInState,omitempty"`
Create map[string]VacationResponse `json:"create,omitempty"`
Update map[string]PatchObject `json:"update,omitempty"`
Destroy []string `json:"destroy,omitempty"`
}
type VacationResponseSetResponse struct {
AccountId string `json:"accountId"`
OldState State `json:"oldState,omitempty"`
NewState State `json:"newState,omitempty"`
Created map[string]VacationResponse `json:"created,omitempty"`
Updated map[string]VacationResponse `json:"updated,omitempty"`
Destroyed []string `json:"destroyed,omitempty"`
NotCreated map[string]SetError `json:"notCreated,omitempty"`
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
NotDestroyed map[string]SetError `json:"notDestroyed,omitempty"`
}
// One of these attributes must be set, but not both.
type DataSourceObject struct {
DataAsText string `json:"data:asText,omitempty"`
DataAsBase64 string `json:"data:asBase64,omitempty"`
}
type UploadObject struct {
Data []DataSourceObject `json:"data"`
Type string `json:"type,omitempty"`
}
type BlobUploadCommand struct {
AccountId string `json:"accountId"`
Create map[string]UploadObject `json:"create"`
}
type BlobUploadCreateResult struct {
Id string `json:"id"`
Type string `json:"type,omitempty"`
Size int `json:"size"`
}
type BlobUploadResponse struct {
AccountId string `json:"accountId"`
Created map[string]BlobUploadCreateResult `json:"created"`
}
const (
BlobPropertyDataAsText = "data:asText"
BlobPropertyDataAsBase64 = "data:asBase64"
// Returns data:asText if the selected octets are valid UTF-8 or data:asBase64.
BlobPropertyData = "data"
BlobPropertySize = "size"
// https://www.iana.org/assignments/http-digest-hash-alg/http-digest-hash-alg.xhtml
BlobPropertyDigestSha256 = "digest:sha256"
// https://www.iana.org/assignments/http-digest-hash-alg/http-digest-hash-alg.xhtml
BlobPropertyDigestSha512 = "digest:sha512"
)
type BlobGetCommand struct {
AccountId string `json:"accountId"`
Ids []string `json:"ids,omitempty"`
Properties []string `json:"properties,omitempty"`
Offset int `json:"offset,omitzero"`
Length int `json:"length,omitzero"`
}
type BlobGetRefCommand struct {
AccountId string `json:"accountId"`
IdRef *ResultReference `json:"#ids,omitempty"`
Properties []string `json:"properties,omitempty"`
Offset int `json:"offset,omitzero"`
Length int `json:"length,omitzero"`
}
type Blob struct {
// The unique identifier of the blob.
Id string `json:"id"`
// (raw octets, must be UTF-8)
DataAsText string `json:"data:asText,omitempty"`
// (base64 representation of octets)
DataAsBase64 string `json:"data:asBase64,omitempty"`
// The base64 encoding of the digest of the octets in the selected range,
// calculated using the SHA-256 algorithm.
DigestSha256 string `json:"digest:sha256,omitempty"`
// The base64 encoding of the digest of the octets in the selected range,
// calculated using the SHA-512 algorithm.
DigestSha512 string `json:"digest:sha512,omitempty"`
// If an encoding problem occured.
//
// The data fields contain a representation of the octets within the selected range
// that are present in the blob.
//
// If the octets selected are not valid UTF-8 (including truncating in the middle of a
// multi-octet sequence) and data or data:asText was requested, then the key isEncodingProblem
// MUST be set to true, and the data:asText response value MUST be null.
//
// In the case where data was requested and the data is not valid UTF-8, then data:asBase64
// MUST be returned.
IsEncodingProblem bool `json:"isEncodingProblem,omitzero"`
// When requesting a range: the isTruncated property in the result MUST be
// set to true to tell the client that the requested range could not be fully satisfied.
IsTruncated bool `json:"isTruncated,omitzero"`
// The number of octets in the entire blob.
Size int `json:"size"`
}
// Picks the best digest if available, or ""
func (b *Blob) Digest() string {
if b.DigestSha512 != "" {
return b.DigestSha512
} else if b.DigestSha256 != "" {
return b.DigestSha256
} else {
return ""
}
}
type BlobGetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A string representing the state on the server for all the data of this type in the
// account (not just the objects returned in this call).
//
// If the data changes, this string MUST change. If the Blob data is unchanged, servers
// SHOULD return the same state string on subsequent requests for this data type.
//
// When a client receives a response with a different state string to a previous call,
// it MUST either throw away all currently cached objects for the type or call
// Blob/changes to get the exact changes.
State State `json:"state,omitempty"`
// An array of the Blob objects requested.
//
// This is the empty array if no objects were found or if the ids argument passed in
// was also an empty array. The results MAY be in a different order to the ids in the
// request arguments. If an identical id is included more than once in the request,
// the server MUST only include it once in either the list or the notFound argument of the response.
List []Blob `json:"list,omitempty"`
// This array contains the ids passed to the method for records that do not exist.
//
// The array is empty if all requested ids were found or if the ids argument passed
// in was either null or an empty array.
NotFound []any `json:"notFound,omitempty"`
}
type BlobDownload struct {
Body io.ReadCloser
Size int
Type string
ContentDisposition string
CacheControl string
}
type UploadedBlob struct {
BlobId string `json:"blobId"`
Size int `json:"size,omitzero"`
Type string `json:"type,omitempty"`
}
// When doing a search on a String property, the client may wish to show the relevant
// section of the body that matches the search as a preview and to highlight any
// matching terms in both this and the subject of the Email.
//
// Search snippets represent this data.
//
// What is a relevant section of the body for preview is server defined. If the server is
// unable to determine search snippets, it MUST return null for both the subject and preview
// properties.
//
// Note that unlike most data types, a SearchSnippet DOES NOT have a property called id.
type SearchSnippet struct {
// The Email id the snippet applies to.
EmailId string `json:"emailId"`
// If text from the filter matches the subject, this is the subject of the Email
// with the following transformations:
//
// 1. Any instance of the following three characters MUST be replaced by an
// appropriate HTML entity: & (ampersand), < (less-than sign), and > (greater-than sign)
// HTML. Other characters MAY also be replaced with an HTML entity form.
// 2. The matching words/phrases from the filter are wrapped in HTML <mark></mark> tags.
//
// If the subject does not match text from the filter, this property is null.
Subject string `json:"subject,omitempty"`
// If text from the filter matches the plaintext or HTML body, this is the
// relevant section of the body (converted to plaintext if originally HTML),
// with the same transformations as the subject property.
//
// It MUST NOT be bigger than 255 octets in size.
//
// If the body does not contain a match for the text from the filter, this property is null.
Preview string `json:"preview,omitempty"`
}
type SearchSnippetGetRefCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// The same filter as passed to Email/query.
Filter EmailFilterElement `json:"filter,omitempty"`
// The ids of the Emails to fetch snippets for.
EmailIdRef *ResultReference `json:"#emailIds,omitempty"`
}
type SearchSnippetGetResponse struct {
AccountId string `json:"accountId"`
List []SearchSnippet `json:"list,omitempty"`
NotFound []string `json:"notFound,omitempty"`
}
type StateChangeType string
const TypeOfStateChange = StateChangeType("StateChange")
type StateChange struct {
// This MUST be the string "StateChange".
Type StateChangeType `json:"@type"`
// A map of an "account id" to an object encoding the state of data types that have
// changed for that account since the last StateChange object was pushed, for each
// of the accounts to which the user has access and for which something has changed.
//
// The value is a map. The keys are the type name "Foo" e.g., "Mailbox" or "Email"),
// and the value is the "state" property that would currently be returned by a call to
// "Foo/get".
//
// The client can compare the new state strings with its current values to see whether
// it has the current data for these types. If not, the changes can then be efficiently
// fetched in a single standard API request (using the /changes type methods).
Changed map[string]map[ObjectType]string `json:"changed"`
// A (preferably short) string that encodes the entire server state visible to the user
// (not just the objects returned in this call).
//
// The purpose of the "pushState" token is to allow a client to immediately get any changes
// that occurred while it was disconnected. If the server does not support "pushState" tokens,
// the client will have to issue a series of "/changes" requests upon reconnection to update
// its state to match that of the server.
PushState State `json:"pushState"`
}
type AddressBookRights struct {
// The user may fetch the ContactCards in this AddressBook.
MayRead bool `json:"mayRead"`
// The user may create, modify or destroy all ContactCards in this AddressBook, or move them to or from this AddressBook.
MayWrite bool `json:"mayWrite"`
// The user may modify the “shareWith” property for this AddressBook.
MayAdmin bool `json:"mayAdmin"`
// The user may delete the AddressBook itself.
MayDelete bool `json:"mayDelete"`
}
// An AddressBook is a named collection of ContactCards.
//
// All ContactCards are associated with one or more AddressBook.
type AddressBook struct {
// The id of the AddressBook (immutable; server-set).
Id string `json:"id"`
// The user-visible name of the AddressBook.
//
// This may be any UTF-8 string of at least 1 character in length and maximum 255 octets in size.
Name string `json:"name"`
// An optional longer-form description of the AddressBook, to provide context in shared environments
// where users need more than just the name.
Description string `json:"description,omitempty"`
// Defines the sort order of AddressBooks when presented in the clients UI, so it is consistent between devices.
//
// The number MUST be an integer in the range 0 <= sortOrder < 2^31.
//
// An AddressBook with a lower order should be displayed before a AddressBook with a higher order in any list
// of AddressBooks in the clients UI.
//
// AddressBooks with equal order SHOULD be sorted in alphabetical order by name.
//
// The sorting should take into account locale-specific character order convention.
//
// Default: 0
SortOrder uint `json:"sortOrder,omitzero"`
// This SHOULD be true for exactly one AddressBook in any account, and MUST NOT be true for more than one
// AddressBook within an account.
//
// The default AddressBook should be used by clients whenever they need to choose an AddressBook for the user
// within this account, and they do not have any other information on which to make a choice.
//
// For example, if the user creates a new contact card, the client may automatically set the card as belonging
// to the default AddressBook from the users primary account.
IsDefault bool `json:"isDefault,omitzero"`
// True if the user has indicated they wish to see this AddressBook in their client.
//
// This SHOULD default to false for AddressBooks in shared accounts the user has access to and true for any
// new AddressBooks created by the user themself.
//
// If false, the AddressBook and its contents SHOULD only be displayed when the user explicitly requests it
// or to offer it for the user to subscribe to.
IsSubscribed bool `json:"isSubscribed"`
// A map of Principal id to rights for principals this AddressBook is shared with.
//
// The principal to which this AddressBook belongs MUST NOT be in this set.
//
// This is null if the AddressBook is not shared with anyone.
//
// May be modified only if the user has the mayAdmin right.
//
// The account id for the principals may be found in the urn:ietf:params:jmap:principals:owner capability
// of the Account to which the AddressBook belongs.
ShareWith map[string]AddressBookRights `json:"shareWith,omitempty"`
// The set of access rights the user has in relation to this AddressBook (server-set).
MyRights AddressBookRights `json:"myRights"`
}
type CalendarRights struct {
// The user may read the free-busy information for this calendar.
MayReadFreeBusy bool `json:"mayReadFreeBusy"`
// The user may fetch the events in this calendar.
MayReadItems bool `json:"mayReadItems"`
// The user may create, modify or destroy all events in this calendar, or move events
// to or from this calendar.
//
// If this is `true`, the `mayWriteOwn`, `mayUpdatePrivate` and `mayRSVP`
// properties MUST all also be `true`.
MayWriteAll bool `json:"mayWriteAll"`
// The user may create, modify or destroy an event on this calendar if either they are
// the owner of the event or the event has no owner.
//
// This means the user may also transfer ownership by updating an event so they are no longer an owner.
MayWriteOwn bool `json:"mayWriteOwn"`
// The user may modify per-user properties on all events in the calendar, even if they would
// not otherwise have permission to modify that event.
//
// These properties MUST all be stored per-user, and changes do not affect any other user of the calendar.
//
// The user may also modify these properties on a per-occurrence basis for recurring events
// (updating the `recurrenceOverrides` property of the event to do so).
MayUpdatePrivate bool `json:"mayUpdatePrivate"`
// The user may modify the following properties of any `Participant` object that corresponds
// to one of the user's `ParticipantIdentity` objects in the account, even if they would not
// otherwise have permission to modify that event.
//
// !- `participationStatus`
// !- `participationComment`
// !- `expectReply`
// !- `scheduleAgent`
// !- `scheduleSequence`
// !- `scheduleUpdated`
//
// If the event has its `mayInviteSelf` property set to `true`, then the user may also add a
// new `Participant` to the event with `scheduleId`/`sendTo` properties that are the same as
// the `scheduleId`/`sendTo` properties of one of the user's `ParticipantIdentity` objects in
// the account.
//
// The `roles` property of the participant MUST only contain `attendee`.
//
// If the event has its `mayInviteOthers` property set to `true` and there is an existing
// `Participant` in the event corresponding to one of the user's `ParticipantIdentity` objects
// in the account, then the user may also add new participants.
//
// The `roles` property of any new participant MUST only contain `attendee`.
//
// The user may also do all of the above on a per-occurrence basis for recurring events
// (updating the recurrenceOverrides property of the event to do so).
MayRSVP bool `json:"mayRSVP"`
// The user may modify the `shareWith` property for this calendar.
MayAdmin bool `json:"mayAdmin"`
// The user may delete the calendar itself.
MayDelete bool `json:"mayDelete"`
}
// A Calendar is a named collection of events.
//
// All events are associated with at least one calendar.
//
// The user is an owner for an event if the `CalendarEvent` object has a `participants`
// property, and one of the `Participant` objects both:
// 1. Has the `owner` role.
// 2. Corresponds to one of the user's `ParticipantIdentity` objects in the account.
//
// An event has no owner if its `participants` property is null or omitted, or if none
// of the `Participant` objects have the `owner` role.
type Calendar struct {
// The id of the calendar (immutable; server-set).
Id string `json:"id"`
// The user-visible name of the calendar.
//
// This may be any UTF-8 string of at least 1 character in length and maximum 255 octets in size.
Name string `json:"name"`
// An optional longer-form description of the calendar, to provide context in shared environments
// where users need more than just the name.
Description string `json:"description,omitempty"`
// A color to be used when displaying events associated with the calendar.
//
// If not null, the value MUST be a case-insensitive color name taken from the set of names
// defined in Section 4.3 of CSS Color Module Level 3 COLORS, or an RGB value in hexadecimal
// notation, as defined in Section 4.2.1 of CSS Color Module Level 3.
//
// The color SHOULD have sufficient contrast to be used as text on a white background.
Color string `json:"color,omitempty"`
// Defines the sort order of calendars when presented in the clients UI, so it is consistent
// between devices.
//
// The number MUST be an integer in the range 0 <= sortOrder < 2^31.
//
// A calendar with a lower order should be displayed before a calendar with a higher order in any
// list of calendars in the clients UI.
//
// Calendars with equal order SHOULD be sorted in alphabetical order by name.
//
// The sorting should take into account locale-specific character order convention.
SortOrder uint `json:"sortOrder,omitzero"`
// True if the user has indicated they wish to see this Calendar in their client.
//
// This SHOULD default to `false` for Calendars in shared accounts the user has access to and `true`
// for any new Calendars created by the user themself.
//
// If false, the calendar SHOULD only be displayed when the user explicitly requests it or to offer
// it for the user to subscribe to.
//
// For example, a company may have a large number of shared calendars which all employees have
// permission to access, but you would only subscribe to the ones you care about and want to be able
// to have normally accessible.
IsSubscribed bool `json:"isSubscribed"`
// Should the calendars events be displayed to the user at the moment?
//
// Clients MUST ignore this property if `isSubscribed` is false.
//
// If an event is in multiple calendars, it should be displayed if `isVisible` is `true`
// for any of those calendars.
//
// default: true
IsVisible bool `json:"isVisible"`
// This SHOULD be true for exactly one calendar in any account, and MUST NOT be true for more
// than one calendar within an account (server-set).
//
// The default calendar should be used by clients whenever they need to choose a calendar
// for the user within this account, and they do not have any other information on which to make
// a choice.
//
// For example, if the user creates a new event, the client may automatically set the event as
// belonging to the default calendar from the users primary account.
IsDefault bool `json:"isDefault,omitzero"`
// Should the calendars events be used as part of availability calculation?
//
// This MUST be one of:
// !- `all``: all events are considered.
// !- `attending``: events the user is a confirmed or tentative participant of are considered.
// !- `none``: all events are ignored (but may be considered if also in another calendar).
//
// This should default to “all” for the calendars in the users own account, and “none” for calendars shared with the user.
IncludeInAvailability IncludeInAvailability `json:"includeInAvailability,omitempty"`
// A map of alert ids to Alert objects (see [@!RFC8984], Section 4.5.2) to apply for events
// where `showWithoutTime` is `false` and `useDefaultAlerts` is `true`.
//
// Ids MUST be unique across all default alerts in the account, including those in other
// calendars; a UUID is recommended.
//
// The "trigger" MUST NOT be an `AbsoluteTrigger`, as this would fire for every event at the same
// time and so does not make sense for a default alert.
//
// If omitted on creation, the default is server dependent.
//
// For example, servers may choose to always default to null, or may copy the alerts from the default calendar.
DefaultAlertsWithTime map[string]jscalendar.Alert `json:"defaultAlertsWithTime,omitempty"`
// A map of alert ids to Alert objects (see [@!RFC8984], Section 4.5.2) to apply for events where
// `showWithoutTime` is `true` and `useDefaultAlerts` is `true`.
//
// Ids MUST be unique across all default alerts in the account, including those in other
// calendars; a UUID is recommended.
//
// The "trigger" MUST NOT be an `AbsoluteTrigger`, as this would fire for every event at the
// same time and so does not make sense for a default alert.
//
// If omitted on creation, the default is server dependent.
//
// For example, servers may choose to always default to null, or may copy the alerts from the default calendar.
DefaultAlertsWithoutTime map[string]jscalendar.Alert `json:"defaultAlertsWithoutTime,omitempty"`
// The time zone to use for events without a time zone when the server needs to resolve them into
// absolute time, e.g., for alerts or availability calculation.
//
// The value MUST be a time zone id from the IANA Time Zone Database TZDB.
//
// If null, the `timeZone` of the accounts associated `Principal` will be used.
//
// Clients SHOULD use this as the default for new events in this calendar if set.
TimeZone string `json:"timeZone,omitempty"`
// A map of `Principal` id to rights for principals this calendar is shared with.
//
// The principal to which this calendar belongs MUST NOT be in this set.
//
// This is null if the calendar is not shared with anyone.
//
// May be modified only if the user has the `mayAdmin` right.
//
// The account id for the principals may be found in the `urn:ietf:params:jmap:principals:owner`
// capability of the `Account` to which the calendar belongs.
ShareWith map[string]CalendarRights `json:"shareWith,omitempty"`
// The set of access rights the user has in relation to this Calendar.
//
// If any event is in multiple calendars, the user has the following rights:
// !- The user may fetch the event if they have the mayReadItems right on any calendar the event is in.
// !- The user may remove an event from a calendar (by modifying the events “calendarIds” property) if the user
// has the appropriate permission for that calendar.
// !- The user may make other changes to the event if they have the right to do so in all calendars to which the
// event belongs.
MyRights *CalendarRights `json:"myRights,omitempty"`
}
// A CalendarEvent object contains information about an event, or recurring series of events,
// that takes place at a particular time.
//
// It is a JSCalendar Event object, as defined in [@!RFC8984], with additional properties.
type CalendarEvent struct {
// The id of the CalendarEvent (immutable; server-set).
//
// The id uniquely identifies a JSCalendar Event with a particular `uid` and
// `recurrenceId` within a particular account.
Id string `json:"id,omitempty"`
// This is only defined if the `id` property is a synthetic id, generated by the
// server to represent a particular instance of a recurring event (immutable; server-set).
//
// This property gives the id of the "real" `CalendarEvent` this was generated from.
BaseEventId string `json:"baseEventId,omitempty"`
// The set of Calendar ids this event belongs to.
//
// An event MUST belong to one or more Calendars at all times (until it is destroyed).
//
// The set is represented as an object, with each key being a Calendar id.
//
// The value for each key in the object MUST be `true`.
CalendarIds map[string]bool `json:"calendarIds,omitempty"`
// If true, this event is to be considered a draft.
//
// The server will not send any scheduling messages to participants or send push notifications
// for alerts.
//
// This may only be set to `true` upon creation.
//
// Once set to `false`, the value cannot be updated to `true`.
//
// This property MUST NOT appear in `recurrenceOverrides`.
IsDraft bool `json:"isDraft,omitzero"`
// Is this the authoritative source for this event (i.e., does it control scheduling for
// this event; the event has not been added as a result of an invitation from another calendar system)?
//
// This is true if, and only if:
// !- the events `replyTo` property is null; or
// !- the account will receive messages sent to at least one of the methods specified in the `replyTo` property of the event.
IsOrigin bool `json:"isOrigin,omitzero"`
// For simple clients that do not implement time zone support.
//
// Clients should only use this if also asking the server to expand recurrences, as you cannot accurately
// expand a recurrence without the original time zone.
//
// This property is calculated at fetch time by the server.
//
// Time zones are political and they can and do change at any time.
//
// Fetching exactly the same property again may return a different results if the time zone data has been updated on the server.
//
// Time zone data changes are not considered `updates` to the event.
//
// If set, the server will convert the UTC date to the event's current time zone and store the local time.
//
// This property is not included in `CalendarEvent/get` responses by default and must be requested explicitly.
//
// Floating events (events without a time zone) will be interpreted as per the time zone given as a `CalendarEvent/get` argument.
//
// Note that it is not possible to accurately calculate the expansion of recurrence rules or recurrence overrides with the
// `utcStart` property rather than the local start time. Even simple recurrences such as "repeat weekly" may cross a
// daylight-savings boundary and end up at a different UTC time. Clients that wish to use "utcStart" are RECOMMENDED to
// request the server expand recurrences.
UtcStart UTCDate `json:"utcStart,omitzero"`
// The server calculates the end time in UTC from the start/timeZone/duration properties of the event.
//
// This property is not included by default and must be requested explicitly.
//
// Like `utcStart`, it is calculated at fetch time if requested and may change due to time zone data changes.
//
// Floating events will be interpreted as per the time zone given as a `CalendarEvent/get` argument.
UtcEnd UTCDate `json:"utcEnd,omitzero"`
jscalendar.Event
}
const (
CalendarEventPropertyId = "id"
CalendarEventPropertyBaseEventId = "baseEventId"
CalendarEventPropertyCalendarIds = "calendarIds"
CalendarEventPropertyIsDraft = "isDraft"
CalendarEventPropertyIsOrigin = "isOrigin"
CalendarEventPropertyUtcStart = "utcStart"
CalendarEventPropertyUtcEnd = "utcEnd"
CalendarEventPropertyType = "type"
CalendarEventPropertyStart = "start"
CalendarEventPropertyDuration = "duration"
CalendarEventPropertyStatus = "status"
CalendarEventPropertyRelatedTo = "relatedTo"
CalendarEventPropertySequence = "sequence"
CalendarEventPropertyShowWithoutTime = "showWithoutTime"
CalendarEventPropertyLocations = "locations"
CalendarEventPropertyVirtualLocations = "virtualLocations"
CalendarEventPropertyRecurrenceId = "recurrenceId"
CalendarEventPropertyRecurrenceIdTimeZone = "recurrenceIdTimeZone"
CalendarEventPropertyRecurrenceRules = "recurrenceRules"
CalendarEventPropertyExcludedRecurrenceRules = "excludedRecurrenceRules"
CalendarEventPropertyRecurrenceOverrides = "recurrenceOverrides"
CalendarEventPropertyExcluded = "excluded"
CalendarEventPropertyPriority = "priority"
CalendarEventPropertyFreeBusyStatus = "freeBusyStatus"
CalendarEventPropertyPrivacy = "privacy"
CalendarEventPropertyReplyTo = "replyTo"
CalendarEventPropertySentBy = "sentBy"
CalendarEventPropertyParticipants = "participants"
CalendarEventPropertyRequestStatus = "requestStatus"
CalendarEventPropertyUseDefaultAlerts = "useDefaultAlerts"
CalendarEventPropertyAlerts = "alerts"
CalendarEventPropertyLocalizations = "localizations"
CalendarEventPropertyTimeZone = "timeZone"
CalendarEventPropertyMayInviteSelf = "mayInviteSelf"
CalendarEventPropertyMayInviteOthers = "mayInviteOthers"
CalendarEventPropertyHideAttendees = "hideAttendees"
CalendarEventPropertyUid = "uid"
CalendarEventPropertyProdId = "prodId"
CalendarEventPropertyCreated = "created"
CalendarEventPropertyUpdated = "updated"
CalendarEventPropertyTitle = "title"
CalendarEventPropertyDescription = "description"
CalendarEventPropertyDescriptionContentType = "descriptionContentType"
CalendarEventPropertyLinks = "links"
CalendarEventPropertyLocale = "locale"
CalendarEventPropertyKeywords = "keywords"
CalendarEventPropertyCategories = "categories"
CalendarEventPropertyColor = "color"
CalendarEventPropertyTimeZones = "timeZones"
)
var CalendarEventProperties = []string{
CalendarEventPropertyId,
CalendarEventPropertyBaseEventId,
CalendarEventPropertyCalendarIds,
CalendarEventPropertyIsDraft,
CalendarEventPropertyIsOrigin,
CalendarEventPropertyUtcStart,
CalendarEventPropertyUtcEnd,
CalendarEventPropertyType,
CalendarEventPropertyStart,
CalendarEventPropertyDuration,
CalendarEventPropertyStatus,
CalendarEventPropertyRelatedTo,
CalendarEventPropertySequence,
CalendarEventPropertyShowWithoutTime,
CalendarEventPropertyLocations,
CalendarEventPropertyVirtualLocations,
CalendarEventPropertyRecurrenceId,
CalendarEventPropertyRecurrenceIdTimeZone,
CalendarEventPropertyRecurrenceRules,
CalendarEventPropertyExcludedRecurrenceRules,
CalendarEventPropertyRecurrenceOverrides,
CalendarEventPropertyExcluded,
CalendarEventPropertyPriority,
CalendarEventPropertyFreeBusyStatus,
CalendarEventPropertyPrivacy,
CalendarEventPropertyReplyTo,
CalendarEventPropertySentBy,
CalendarEventPropertyParticipants,
CalendarEventPropertyRequestStatus,
CalendarEventPropertyUseDefaultAlerts,
CalendarEventPropertyAlerts,
CalendarEventPropertyLocalizations,
CalendarEventPropertyTimeZone,
CalendarEventPropertyMayInviteSelf,
CalendarEventPropertyMayInviteOthers,
CalendarEventPropertyHideAttendees,
CalendarEventPropertyUid,
CalendarEventPropertyProdId,
CalendarEventPropertyCreated,
CalendarEventPropertyUpdated,
CalendarEventPropertyTitle,
CalendarEventPropertyDescription,
CalendarEventPropertyDescriptionContentType,
CalendarEventPropertyLinks,
CalendarEventPropertyLocale,
CalendarEventPropertyKeywords,
CalendarEventPropertyCategories,
CalendarEventPropertyColor,
CalendarEventPropertyTimeZones,
}
// A ParticipantIdentity stores information about a URI that represents the user within that account in an events participants.
type ParticipantIdentity struct {
// The id of the ParticipantIdentity (immutable; server-set).
Id string `json:"id"`
// The display name of the participant to use when adding this participant to an event, e.g. "Joe Bloggs".
//
// default:
Name string `json:"name,omitempty"`
// The URI that represents this participant for scheduling.
//
// This URI MAY also be the URI for one of the sendTo methods.
ScheduleId string `json:"scheduleId"`
// Represents methods by which the participant may receive invitations and updates to an event.
//
// The keys in the property value are the available methods and MUST only contain ASCII alphanumeric
// characters (`A-Za-z0-9`).
//
// The value is a URI for the method specified in the key.
SendTo map[string]string `json:"sendTo,omitempty"`
// This SHOULD be true for exactly one participant identity in any account, and MUST NOT be true for more
// than one participant identity within an account (server-set).
//
// The default identity should be used by clients whenever they need to choose an identity for the user
// within this account, and they do not have any other information on which to make a choice.
//
// For example, if creating a scheduled event in this account, the default identity may be automatically
// added as an owner. (But the client may ignore this if, for example, it has its own feature to allow
// users to choose which identity to use based on the invitees.)
IsDefault bool `json:"isDefault,omitzero"`
}
type CalendarAlert struct {
// This MUST be the string `CalendarAlert`.
Type TypeOfCalendarAlert `json:"@type,omitempty"`
// The account id for the calendar in which the alert triggered.
AccountId string `json:"accountId"`
// The CalendarEvent id for the alert that triggered.
//
// Note, for a recurring event this is the id of the base event, never a synthetic id for a particular instance.
CalendarEventId string `json:"calendarEventId"`
// The uid property of the CalendarEvent for the alert that triggered.
Uid string `json:"uid"`
// The `recurrenceId` for the instance of the event for which this alert is being
// triggered, or null if the event is not recurring.
RecurrenceId LocalDate `json:"recurrenceId,omitzero"`
// The id for the alert that triggered.
AlertId string `json:"alertId"`
}
type Person struct {
// The name of the person who made the change.
Name string `json:"name"`
// The email of the person who made the change, or null if no email is available.
Email string `json:"email,omitempty"`
// The id of the `Principal` corresponding to the person who made the change, if any.
//
// This will be null if the change was due to receving an iTIP message.
PrincipalId string `json:"principalId,omitempty"`
// The `scheduleId` URI of the person who made the change, if any.
//
// This will normally be set if the change was made due to receving an iTIP message.
ScheduleId string `json:"scheduleId,omitempty"`
}
type CalendarEventNotification struct {
// The id of the `CalendarEventNotification`.
Id string `json:"id"`
// The time this notification was created.
Created UTCDate `json:"created,omitzero"`
// Who made the change.
ChangedBy *Person `json:"person,omitempty"`
// Comment sent along with the change by the user that made it.
//
// (e.g. `COMMENT` property in an iTIP message), if any.
Comment string `json:"comment,omitempty"`
// `CalendarEventNotification` type.
//
// This MUST be one of
// !- `created`
// !- `updated`
// !- `destroyed`
Type CalendarEventNotificationTypeOption `json:"type"`
// The id of the CalendarEvent that this notification is about.
//
// If the change only affects a single instance of a recurring event, the server MAY set the
// `event` and `event`atch properties for just that instance; the `calendarEventId` MUST
// still be for the base event.
CalendarEventId string `json:"calendarEventId"`
// Is this event a draft? (created/updated only)
IsDraft bool `json:"isDraft,omitzero"`
// The data before the change (if updated or destroyed),
// or the data after creation (if created).
Event *jscalendar.Event `json:"event,omitempty"`
// A patch encoding the change between the data in the event property,
// and the data after the update (updated only).
EventPatch PatchObject `json:"eventPatch,omitempty"`
}
// Denotes the task list has a special purpose.
//
// This MUST be one of the following:
// !- `inbox`: This is the principals default task list;
// !- `trash`: This task list holds messages the user has discarded;
type TaskListRole string
const (
// This is the principals default task list.
TaskListRoleInbox = TaskListRole("inbox")
// This task list holds messages the user has discarded.
TaskListRoleTrash = TaskListRole("trash")
)
var (
DefaultWorkflowStatuses = []string{
"completed",
"failed",
"in-process",
"needs-action",
"cancelled",
"pending",
}
)
type TaskRights struct {
// The user may fetch the tasks in this task list.
MayReadItems bool `json:"mayReadItems"`
// The user may create, modify or destroy all tasks in this task list,
// or move tasks to or from this task list.
//
// If this is `true`, the `mayWriteOwn`, `mayUpdatePrivate` and `mayRSVP` properties
// MUST all also be `true`.
MayWriteAll bool `json:"mayWriteAll"`
// The user may create, modify or destroy a task on this task list if either they are
// the owner of the task (see below) or the task has no owner.
//
// This means the user may also transfer ownership by updating a task so they are no longer
// an owner.
MayWriteOwn bool `json:"mayWriteOwn"`
// The user may modify the following properties on all tasks in the task list, even
// if they would not otherwise have permission to modify that task.
//
// These properties MUST all be stored per-user, and changes do not affect any other user of the task list.
//
// The user may also modify the above on a per-occurrence basis for recurring tasks
// (updating the `recurrenceOverrides` property of the task to do so).
MayUpdatePrivate bool `json:"mayUpdatePrivate"`
// The user may modify the following properties of any `Participant` object that corresponds
// to one of the users `ParticipantIdentity` objects in the account, even if they would not
// otherwise have permission to modify that task
// !- `participationStatus`
// !- `participationComment`
// !- `expectReply`
//
// If the task has its `mayInviteSelf` property set to true, then the user may also add a new
// `Participant` to the task with a `sendTo` property that is the same as the `sendTo` property
// of one of the users `ParticipantIdentity` objects in the account.
// The `roles` property of the participant MUST only contain `attendee`.
//
// If the task has its `mayInviteOthers` property set to `true` and there is an existing
// `Participant` in the task corresponding to one of the users `ParticipantIdentity` objects
// in the account, then the user may also add new participants.
// The `roles` property of any new participant MUST only contain `attendee`.
//
// The user may also do all of the above on a per-occurrence basis for recurring tasks
// (updating the `recurrenceOverrides` property of the task to do so).
MayRSVP bool `json:"mayRSVP"`
// The user may modify sharing for this task list.
MayAdmin bool `json:"mayAdmin"`
// The user may delete the task list itself (server-set).
//
// This property MUST be false if the account to which this task list belongs has the `isReadOnly`
// property set to true.
MayDelete bool `json:"mayDelete"`
}
type TaskList struct {
// The id of the task list (immutable; server-set).
Id string `json:"id,omitempty"`
// Denotes the task list has a special purpose.
//
// This MUST be one of the following:
// !- `inbox`: This is the principals default task list;
// !- `trash`: This task list holds messages the user has discarded;
Role TaskListRole `json:"role,omitempty"`
// The user-visible name of the task list.
//
// This may be any UTF-8 string of at least 1 character in length and maximum 255 octets in size.
Name string `json:"name,omitempty"`
// An optional longer-form description of the task list, to provide context in shared environments
// where users need more than just the name.
Description string `json:"description,omitempty"`
// A color to be used when displaying tasks associated with the task list.
//
// If not null, the value MUST be a case-insensitive color name taken from the set of names defined
// in Section 4.3 of CSS Color Module Level 3 COLORS, or an RGB value in hexadecimal notation,
// as defined in Section 4.2.1 of CSS Color Module Level 3.
//
// The color SHOULD have sufficient contrast to be used as text on a white background.
Color string `json:"color,omitempty"`
// A map of keywords to the colors used when displaying the keywords associated to a task.
//
// The same considerations, as for `color` above, apply.
KeywordColors map[string]string `json:"keywordColors,omitempty"`
// A map of categories to the colors used when displaying the categories associated to a task.
//
// The same considerations, as for `color` above, apply.
CategoryColors map[string]string `json:"categoryColors,omitempty"`
// Defines the sort order of task lists when presented in the clients UI, so it is consistent
// between devices.
//
// The number MUST be an integer in the range 0 ≤ sortOrder < 2^31.
//
// A task list with a lower order should be displayed before a list with a higher order in any list
// of task lists in the clients UI.
//
// Task lists with equal order SHOULD be sorted in alphabetical order by name.
//
// The sorting should take into account locale-specific character order convention.
SortOrder uint `json:"sortOrder,omitzero"`
// Has the user indicated they wish to see this task list in their client?
//
// This SHOULD default to false for task lists in shared accounts the user has access to,
// and true for any new task list created by the user themselves.
//
// If false, the task list should only be displayed when the user explicitly
// requests it or to offer it for the user to subscribe to.
IsSubscribed bool `json:"isSubscribed,omitzero"`
// The time zone to use for tasks without a time zone when the server needs to resolve them
// into absolute time, e.g., for alerts or availability calculation.
//
// The value MUST be a time zone id from the IANA Time Zone Database TZDB.
//
// If null, the timeZone of the accounts associated Principal will be used.
//
// Clients SHOULD use this as the default for new tasks in this task list, if set.
TimeZone string `json:"timeZone,omitempty"`
// Defines the allowed values for `workflowStatus`.
//
// The default values are based on the values defined within [@!RFC8984], Section 5.2.5 and `pending`.
//
// `pending` indicates the task has been created and accepted, but it currently is on-hold.
//
// As naming and workflows differ between systems, mapping the status correctly to the present values
// of the `Task` can be challenging. In the most simple case, a task system may support merely two states - `done`
// and `not-done`.
//
// On the other hand, statuses and their semantic meaning can differ between systems or task lists (e.g. projects).
//
// In case of uncertainty, here are some recommendations for mapping commonly observed values that can help
// during implementation:
// !- `completed`: `done` (most simple case), `closed`, `verified`, …
// !- `in-process`: `in-progress`, `active`, `assigned`, …
// !- `needs-action`: `not-done` (most simple case), `not-started`, `new`, …
// !- `pending`: `waiting`, `deferred`, `on-hold`, `paused`, …
WorkflowStatuses []string `json:"workflowStatuses,omitempty"`
// A map of `Principal` id to rights for principals this task list is shared with.
//
// The principal to which this task list belongs MUST NOT be in this set.
//
// This is null if the task list is not shared with anyone.
//
// May be modified only if the user has the `mayAdmin` right.
//
// The account id for the principals may be found in the `urn:ietf:params:jmap:principals:owner` capability
// of the `Account` to which the task list belongs.
ShareWith map[string]TaskRights `json:"shareWith,omitempty"`
// The set of access rights the user has in relation to this `TaskList`.
//
// The user may fetch the task if they have the `mayReadItems` right on any task list the task is in.
//
// The user may remove a task from a task list (by modifying the tasks `taskListId` property) if the user has the
// appropriate permission for that task list.
//
// The user may make other changes to the task if they have the right to do so in all task list to which the task belongs.
MyRights *TaskRights `json:"myRights,omitempty"`
// A map of alert ids to `Alert` objects (see [@!RFC8984], Section 4.5.2) to apply for tasks
// where `showWithoutTime` is `false` and `useDefaultAlerts` is `true`.
//
// Ids MUST be unique across all default alerts in the account, including those in other task
// lists; a UUID is recommended.
//
// If omitted on creation, the default is server dependent.
//
// For example, servers may choose to always default to null, or may copy the alerts from the default task list.
DefaultAlertsWithTime map[string]jscalendar.Alert `json:"defaultAlertsWithTime,omitempty"`
// A map of alert ids to `Alert` objects (see [@!RFC8984], Section 4.5.2) to apply for tasks
// where `showWithoutTime` is `true` and `useDefaultAlerts` is `true`.
//
// Ids MUST be unique across all default alerts in the account, including those in other task
// lists; a UUID is recommended.
//
// If omitted on creation, the default is server dependent. For example, servers may choose to always
// default to `null`, or may copy the alerts from the default task list.
DefaultAlertsWithoutTime map[string]jscalendar.Alert `json:"defaultAlertsWithoutTime,omitempty"`
}
type TypeOfChecklist string
type TypeOfCheckItem string
type TypeOfTaskPerson string
type TypeOfComment string
type TaskNotificationTypeOption string
const ChecklistType = TypeOfChecklist("Checklist")
const CheckItemType = TypeOfCheckItem("CheckItem")
const TaskPersonType = TypeOfTaskPerson("Person")
const CommentType = TypeOfComment("Comment")
const TaskNotificationTypeOptionCreated = TaskNotificationTypeOption("created")
const TaskNotificationTypeOptionUpdated = TaskNotificationTypeOption("updated")
const TaskNotificationTypeOptionDestroyed = TaskNotificationTypeOption("destroyed")
// The Person object has the following properties of which either principalId or uri MUST be defined.
type TaskPerson struct {
// Specifies the type of this object, this MUST be `Person`.
Type TypeOfTaskPerson `json:"@type,omitempty"`
// The name of the person.
Name string `json:"name,omitempty"`
// A URI value that identifies the person.
//
// This SHOULD be the `scheduleId` of the participant that this item was assigned to.
Uri string `json:"uri,omitempty"`
// The id of the Principal corresponding to the person, if any.
PrincipalId string `json:"principalId,omitempty"`
}
type Comment struct {
// Specifies the type of this object, this MUST be `Comment`.
Type TypeOfComment `json:"@type,omitempty"`
// The free text value of this comment.
Message string `json:"message"`
// The date and time when this note was created.
Created UTCDate `json:"created,omitzero"`
// The date and time when this note was updated.
Updated UTCDate `json:"updated,omitzero"`
// The author of this comment.
Author *TaskPerson `json:"author,omitempty"`
}
type CheckItem struct {
// Specifies the type of this object, this MUST be `CheckItem`.
Type TypeOfCheckItem `json:"@type,omitempty"`
// Title of the item.
Title string `json:"title,omitempty"`
// Defines the sort order of `CheckItem` when presented in the clients UI.
//
// The number MUST be an integer in the range 0 <= sortOrder < 2^31.
//
// An item with a lower order should be displayed before an item with a higher order.
//
// Items with equal order SHOULD be sorted in alphabetical order by name.
//
// The sorting should take into account locale-specific character order convention.
SortOrder uint `json:"sortOrder,omitzero"`
// The date and time when this item was updated.
Updated UTCDate `json:"updated,omitzero"`
IsComplete bool `json:"isComplete,omitzero"`
// The person that this item is assigned to.
//
// The `Person` object has the following properties of which either `principalId` or `uri`
// MUST be defined.
Assignee *TaskPerson `json:"assignee,omitempty"`
// Free-text comments associated with this task.
Comments map[string]Comment `json:"comments,omitempty"`
}
type Checklist struct {
// Specifies the type of this object, this MUST be `Checklist`.
Type TypeOfChecklist `json:"@type,omitempty"`
// Title of the list.
Title string `json:"title,omitempty"`
// The items of the check list.
CheckItems []CheckItem `json:"checkItems,omitempty"`
}
// A `Task` object contains information about a task.
//
// It is a JSTask object, as defined in [@!RFC8984]. However, as use-cases of task systems vary, this
// Section defines relevant parts of the JSTask object to implement the core task capability as well
// as several extensions to it.
//
// Only the core capability MUST be implemented by any task system.
//
// Implementers can choose the extensions that fit their own use case.
//
// For example, the recurrence extension allows having a `Task` object represent a series of recurring `Task`s.
type Task struct {
// The id of the Task.
//
// This property is immutable.
//
// The id uniquely identifies a JSTask with a particular `uid` and `recurrenceId` within a particular account.
Id string `json:"id"`
// The `TaskList` id this task belongs to.
//
// A task MUST belong to exactly one `TaskList` at all times (until it is destroyed).
TaskListId string `json:"taskListId"`
// If `true`, this task is to be considered a draft.
//
// The server will not send any push notifications for alerts.
//
// This may only be set to true upon creation.
//
// Once set to `false`, the value cannot be updated to `true`.
//
// This property MUST NOT appear in `recurrenceOverrides`.
IsDraft bool `json:"isDraft,omitzero"`
UtcStart UTCDate `json:"utcStart,omitzero"`
UtcDue UTCDate `json:"utcDue,omitzero"`
SortOrder uint `json:"sortOrder,omitzero"`
WorkflowStatus string `json:"workflowStatus,omitempty"`
jscalendar.Task
// This specifies the estimated amount of work the task takes to complete.
//
// In Agile software development or Scrum, it is known as complexity or story points.
//
// The number has no actual unit, but a larger number means more work.
EstimatedWork uint `json:"estimatedWork,omitzero"`
// This specifies the impact or severity of the task, but does not say anything
// about the actual prioritization.
//
// Some examples are: `minor`, `trivial`, `major` or `block`.
//
// Usually, the priority of a task is based upon its impact and urgency.
Impact string `json:"impact,omitempty"`
// A map of Checklist IDs to Checklist objects, containing checklist items.
Checklists map[string]Checklist `json:"checklists,omitempty"`
// This is only defined if the id property is a synthetic id, generated by the server
// to represent a particular instance of a recurring Task (immutable; server-set).
//
// This property gives the id of the “real” Task this was generated from.
BaseTaskId string `json:"baseTaskId,omitempty"`
// Is this the authoritative source for this task (i.e., does it control scheduling
// for this task; the task has not been added as a result of an invitation from another
// task management system)?
//
// This is `true` if, and only if:
// !- the tasks “replyTo” property is null; or
// !- the account will receive messages sent to at least one of the methods specified in
// the `replyTo` property of the task.
IsOrigin bool `json:"isOrigin,omitzero"`
// If true, any user that has access to the task may add themselves to it as a participant
// with the `attendee` role.
//
// This property MUST NOT be altered in the `recurrenceOverrides`; it may only be set on the master object.
//
// This indicates the task will accept “party crasher” RSVPs via iTIP, subject to any other domain-specific
// restrictions, and users may add themselves to the task via JMAP as long as they have the `mayRSVP`
// permission for the task list.
//
// default: false
MayInviteSelf bool `json:"mayInviteSelf,omitzero"`
// If true, any current participant with the `attendee` role may add new participants with
// the `attendee` role to the task.
//
// This property MUST NOT be altered in the `recurrenceOverrides`; it may only be set on the master object.
//
// default: false
MayInviteOthers bool `json:"mayInviteOthers,omitzero"`
// If true, only the owners of the task may see the full set of participants.
//
// Other sharees of the task may only see the owners and themselves.
//
// This property MUST NOT be altered in the `recurrenceOverrides`; it may only be set on the master object.
HideAttendees bool `json:"hideAttendees,omitzero"`
}
// The `TaskNotification` data type records changes made by external entities to tasks in task lists
// the user is subscribed to.
//
// Notifications are stored in the same `Account` as the `Task` that was changed.
type TaskNotification struct {
// The id of the `TaskNotification`.
Id string `json:"id"`
// The time this notification was created.
Created UTCDate `json:"created,omitzero"`
// Who made the change.
ChangedBy *TaskPerson `json:"changedBy,omitempty"`
// Comment sent along with the change by the user that made it.
//
// (e.g. `COMMENT` property in an iTIP message), if any.
Comment string `json:"comment,omitempty"`
// This MUST be one of
// !- `created`
// !- `updated`
// !- `destroyed`
Type TaskNotificationTypeOption `json:"type"`
// The id of the Task that this notification is about.
TaskId string `json:"taskId"`
// Is this task a draft? (created/updated only)
IsDraft bool `json:"isDraft,omitzero"`
// The data before the change (if updated or destroyed), or the data after creation (if created).
Task *jscalendar.Task `json:"task,omitempty"`
// A patch encoding the change between the data in the task property, and the data after the update updated only).
TaskPatch PatchObject `json:"taskPatch,omitempty"`
}
// A Principal represents an individual, group, location (e.g. a room), resource (e.g. a projector) or other entity
// in a collaborative environment.
//
// Sharing in JMAP is generally configured by assigning rights to certain data within an account to other principals,
// for example a user may assign permission to read their calendar to a principal representing another user, or their team.
//
// In a shared environment such as a workplace, a user may have access to a large number of principals.
//
// In most systems the user will have access to a single `Account` containing `Principal` objects, but they may
// have access to multiple if, for example, aggregating data from different places.
type Principal struct {
// The id of the principal.
Id string `json:"id"`
// `Principal` type.
//
// This MUST be one of the following values:
// !- `individual`: This represents a single person.
// !- `group`: This represents a group of people.
// !- `resource`: This represents some resource, e.g. a projector.
// !- `location`: This represents a location.
// !- `other`: This represents some other undefined principal.
Type PrincipalTypeOption `json:"type"`
// The name of the principal, e.g. `"Jane Doe"`, or `"Room 4B"`.
Name string `json:"name"`
// A longer description of the principal, for example details about the
// facilities of a resource, or null if no description available.
Description string `json:"description,omitempty"`
// An email address for the principal, or null if no email is available.
Email string `json:"email,omitempty"`
// The time zone for this principal, if known.
//
// If not null, the value MUST be a time zone id from the IANA Time Zone Database TZDB.
TimeZone string `json:"timeZone,omitempty"`
// A map of JMAP capability URIs to domain specific information about the principal in relation
// to that capability, as defined in the document that registered the capability.
Capabilities map[string]any `json:"capabilities,omitempty"`
// A map of account id to `Account` object for each JMAP Account containing data for
// this principal that the user has access to, or null if none.
Accounts map[string]Account `json:"accounts,omitempty"`
}
type ShareChangePerson struct {
// The name of the person who made the change.
Name string `json:"name"`
// The email of the person who made the change, or null if no email is available.
Email string `json:"email,omitempty"`
// The id of the Principal corresponding to the person who made the change, or null if no associated principal.
PrincipalId string `json:"principalId,omitempty"`
}
type ShareNotification struct {
// The id of the `ShareNotification`.
Id string `json:"id"`
// The time this notification was created.
Created UTCDate `json:"created,omitzero"`
// Who made the change.
ChangedBy ShareChangePerson `json:"changedBy"`
// The name of the data type for the object whose permissions have changed, e.g. `Calendar` or `Mailbox`.
ObjectType ObjectType `json:"objectType"`
// The id of the account where this object exists.
ObjectAccountId string `json:"objectAccountId"`
// The id of the object that this notification is about.
ObjectId string `json:"objectId"`
// The name of the object at the time the notification was made.
Name string `json:"name"`
// The `myRights` property of the object for the user before the change.
OldRights map[string]bool `json:"oldRights,omitempty"`
// The `myRights` property of the object for the user after the change.
NewRights map[string]bool `json:"newRights,omitempty"`
}
// TODO unused
type Shareable struct {
// Has the user indicated they wish to see this data?
//
// The initial value for this when data is shared by another user is implementation dependent,
// although data types may give advice on appropriate defaults.
IsSubscribed bool `json:"isSubscribed,omitzero"`
// The set of permissions the user currently has.
//
// Appropriate permissions are domain specific and must be defined per data type.
MyRights map[string]bool `json:"myRights,omitempty"`
// A map of principal id to rights to give that principal, or null if not shared with anyone.
//
// The account id for the principal id can be found in the capabilities of the `Account` this object is in.
//
// Users with appropriate permission may set this property to modify who the data is shared with.
//
// The principal that owns the account this data is in MUST NOT be in the set of sharees; their rights are implicit.
ShareWith map[string]map[string]bool `json:"shareWith,omitempty"`
}
// The Quota is an object that displays the limit set to an account usage.
//
// It then shows as well the current usage in regard to that limit.
type Quota struct {
// The unique identifier for this object.
Id string `json:"id"`
// The resource type of the quota.
ResourceType ResourceType `json:"resourceType"`
// The current usage of the defined quota, using the `resourceType` defined as unit of measure.
//
// Computation of this value is handled by the server.
Used uint `json:"used"`
// The hard limit set by this quota, using the `resourceType` defined as unit of measure.
//
// Objects in scope may not be created or updated if this limit is reached.
HardLimit uint `json:"hardLimit"`
// The Scope data type is used to represent the entities the quota applies to.
//
// It is defined as a "String" with values from the following set:
// !- `account`: The quota information applies to just the client's account.
// !- `domain`: The quota information applies to all accounts sharing this domain.
// !- `global`: The quota information applies to all accounts belonging to the server.
Scope Scope `json:"scope"`
// The name of the quota.
//
// Useful for managing quotas and using queries for searching.
Name string `json:"name"`
// A list of all the type names as defined in the "JMAP Types Names" registry
// (e.g., `Email`, `Calendar`, etc.) to which this quota applies.
//
// This allows the quotas to be assigned to distinct or shared data types.
//
// The server MUST filter out any types for which the client did not request the associated capability
// in the `using` section of the request.
//
// Further, the server MUST NOT return Quota objects for which there are no types recognized by the client.
Types []ObjectType `json:"types,omitempty"`
// The warn limit set by this quota, using the `resourceType` defined as unit of measure.
//
// It can be used to send a warning to an entity about to reach the hard limit soon, but with no
// action taken yet.
//
// If set, it SHOULD be lower than the `softLimit` (if present and different from null) and the `hardLimit`.
WarnLimit uint `json:"warnLimit,omitzero"`
// The soft limit set by this quota, using the `resourceType` defined as unit of measure.
//
// It can be used to still allow some operations but refuse some others.
//
// What is allowed or not is up to the server.
//
// For example, it could be used for blocking outgoing events of an entity (sending emails, creating
// calendar events, etc.) while still receiving incoming events (receiving emails, receiving calendars
// events, etc.).
//
// If set, it SHOULD be higher than the `warnLimit` (if present and different from null) but lower
// than the `hardLimit`.
SoftLimit uint `json:"softLimit,omitzero"`
// Arbitrary, free, human-readable description of this quota.
//
// It might be used to explain where the different limits come from and explain the entities and data
// types this quota applies to.
//
// The description MUST be encoded in UTF-8 [RFC3629] as described in [RFC8620], Section 1.5, and
// selected based on an `Accept-Language` header in the request (as defined in [RFC9110], Section 12.5.4)
// or out-of-band information about the user's language or locale.
Description string `json:"description,omitempty"`
}
// See [RFC8098] for the exact meaning of these different fields.
//
// These fields are defined as case insensitive in [RFC8098] but are case sensitive in this RFC
// and MUST be converted to lowercase by "MDN/parse".
type Disposition struct {
ActionMode ActionMode `json:"actionMode,omitempty"`
SendingMode SendingMode `json:"sendingMode,omitempty"`
Type DispositionTypeOption `json:"type,omitempty"`
}
// Message Disposition Notifications (MDNs) are defined in [RFC8098] and are used as "read receipts",
// "acknowledgements", or "receipt notifications".
//
// A client can come across MDNs in different ways:
// 1. When receiving an email message, an MDN can be sent to the sender. This specification defines an `MDN/send` method to cover this case.
// 2. When sending an email message, an MDN can be requested. This must be done with the help of a header field, as already specified by [RFC8098];
// the header field can already be handled by guidance in [RFC8621].
// 3. When receiving an MDN, the MDN could be related to an existing sent message. This is already covered by [RFC8621] in the
// `EmailSubmission` object. A client might want to display detailed information about a received MDN.
// This specification defines an `MDN/parse` method to cover this case.
type MDN struct {
// The `Email` id of the received message to which this MDN is related.
//
// This property MUST NOT be null for `MDN/send` but MAY be null in the response from the `MDN/parse` method.
ForEmailId string `json:"forEmailId,omitempty"`
// The subject used as `Subject` header field for this MDN.
Subject string `json:"subject,omitempty"`
// The human-readable part of the MDN, as plain text.
TextBody string `json:"textBody,omitempty"`
// If true, the content of the original message will appear in the third component of the `multipart/report` generated
// for the MDN.
//
// See [RFC8098] for details and security considerations.
IncludeOriginalMessage bool `json:"includeOriginalMessage,omitzero"`
// The name of the Mail User Agent (MUA) creating this MDN.
//
// It is used to build the MDN report part of the MDN.
//
// Note that a null value may have better privacy properties.
ReportingUA string `json:"reportingUA,omitempty"`
// The object containing the diverse MDN disposition options.
Disposition Disposition `json:"disposition"`
// The name of the gateway or Message Transfer Agent (MTA) that translated a foreign (non-Internet)
// message disposition notification into this MDN (server-set).
MdnGateway string `json:"mdnGateway,omitempty"`
// The original recipient address as specified by the sender of the message for which the MDN is being issued (server-set).
OriginalRecipient string `json:"originalRecipient,omitempty"`
// The recipient for which the MDN is being issued.
//
// If set, it overrides the value that would be calculated by the server from the `Identity` defined
// in the `MDN/send` method, unless explicitly set by the client.
FinalRecipient string `json:"finalRecipient,omitempty"`
// The `Message-ID` header field [RFC5322] (not the JMAP id) of the message for which the MDN is being issued.
OriginalMessageId string `json:"originalMessageId,omitempty"`
// Additional information in the form of text messages when the `error` disposition modifier appears.
Error []string `json:"error,omitempty"`
// The object where keys are extension-field names, and values are extension-field values (see [RFC8098], Section 3.3).
ExtensionFields map[string]string `json:"extensionFields,omitempty"`
}
type SendMDN struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// The id of the `Identity` to associate with these MDNs.
//
// The server will use this identity to define the sender of the MDNs and to set the `finalRecipient` field.
IdentityId string `json:"identityId"`
// A map of the creation id (client specified) to MDN objects.
Send map[string]MDN `json:"send,omitempty"`
// A map of the id to an object containing properties to update on the `Email` object referenced by the `MDN/send`
// if the sending succeeds.
//
// This will always be a backward reference to the creation id.
OnSuccessUpdateEmail map[string]PatchObject `json:"onSuccessUpdateEmail,omitempty"`
}
type QuotaGetCommand struct {
AccountId string `json:"accountId"`
Ids []string `json:"ids,omitempty"`
}
type QuotaGetResponse struct {
AccountId string `json:"accountId"`
State State `json:"state,omitempty"`
List []Quota `json:"list,omitempty"`
NotFound []string `json:"notFound,omitempty"`
}
type AddressBookGetCommand struct {
AccountId string `json:"accountId"`
Ids []string `json:"ids,omitempty"`
}
type AddressBookGetResponse struct {
AccountId string `json:"accountId"`
State State `json:"state,omitempty"`
List []AddressBook `json:"list,omitempty"`
NotFound []string `json:"notFound,omitempty"`
}
type ContactCardComparator struct {
// The name of the property on the objects to compare.
Property string `json:"property,omitempty"`
// If true, sort in ascending order.
//
// Optional; default value: true.
//
// If false, reverse the comparators results to sort in descending order.
IsAscending bool `json:"isAscending,omitempty"`
// The identifier, as registered in the collation registry defined in [RFC4790],
// for the algorithm to use when comparing the order of strings.
//
// Optional; default is server dependent.
//
// The algorithms the server supports are advertised in the capabilities object returned
// with the Session object.
//
// [RFC4790]: https://www.rfc-editor.org/rfc/rfc4790.html
Collation string `json:"collation,omitempty"`
// ContactCard-specific: The “created” date on the ContactCard.
Created time.Time `json:"created,omitzero"`
// ContactCard-specific: The "updated” date on the ContactCard.
Updated time.Time `json:"updated,omitzero"`
}
type ContactCardFilterElement interface {
_isAContactCardFilterElement() // marker method
IsNotEmpty() bool
}
type ContactCardFilterCondition struct {
// An AddressBook id.
//
// A card must be in this address book to match the condition.
InAddressBook string `json:"inAddressBook,omitempty"`
// A card must have this string exactly as its uid to match.
Uid string `json:"uid,omitempty"`
// A card must have a “members” property that contains this string as one of the uids in the set to match.
HasMember string `json:"hasMember,omitempty"`
// A card must have a type property that equals this string exactly to match.
Kind string `json:"kind,omitempty"`
// The “created” date-time of the ContactCard must be before this date-time to match the condition.
CreatedBefore UTCDate `json:"createdBefore,omitzero"`
// The “created” date-time of the ContactCard must be the same or after this date-time to match the condition.
CreatedAfter UTCDate `json:"createdAfter,omitzero"`
// The “updated” date-time of the ContactCard must be before this date-time to match the condition.
UpdatedBefore UTCDate `json:"updatedBefore,omitzero"`
// The “updated” date-time of the ContactCard must be the same or after this date-time to match the condition.
UpdatedAfter UTCDate `json:"updatedAfter,omitzero"`
// A card matches this condition if the text matches with text in the card.
Text string `json:"text,omitempty"`
// A card matches this condition if the value of any NameComponent in the “name” property, or the
// “full” property in the “name” property of the card matches the value.
Name string `json:"name,omitempty"`
// A card matches this condition if the value of a NameComponent with kind “given” inside the “name” property of
// the card matches the value.
NameGiven string `json:"name/given,omitempty"`
// A card matches this condition if the value of a NameComponent with kind “surname” inside the “name” property
// of the card matches the value.
NameSurname string `json:"name/surname,omitempty"`
// A card matches this condition if the value of a NameComponent with kind “surname2” inside the “name” property
// of the card matches the value.
NameSurname2 string `json:"name/surname2,omitempty"`
// A card matches this condition if the “name” of any NickName in the “nickNames” property of the card matches the value.
NickName string `json:"nickName,omitempty"`
// A card matches this condition if the “name” of any Organization in the “organizations” property of the card
// matches the value.
Organization string `json:"organization,omitempty"`
// A card matches this condition if the “address” or “label” of any EmailAddress in the “emails” property of the
// card matches the value.
Email string `json:"email,omitempty"`
// A card matches this condition if the “number” or “label” of any Phone in the “phones” property of the card
// matches the value.
Phone string `json:"phone,omitempty"`
// A card matches this condition if the “service”, “uri”, “user”, or “label” of any OnlineService in the
// “onlineServices” property of the card matches the value.
OnlineService string `json:"onlineService,omitempty"`
// A card matches this condition if the value of any StreetComponent in the “street” property, or the “locality”,
// “region”, “country”, or “postcode” property in any Address in the “addresses” property of the card matches the value.
Address string `json:"address,omitempty"`
// A card matches this condition if the “note” of any Note in the “notes” property of the card matches the value.
Note string `json:"note,omitempty"`
}
func (f ContactCardFilterCondition) _isAContactCardFilterElement() {
}
func (f ContactCardFilterCondition) IsNotEmpty() bool {
if len(f.InAddressBook) != 0 {
return true
}
if f.Uid != "" {
return true
}
if f.HasMember != "" {
return true
}
if f.Kind != "" {
return true
}
if f.CreatedBefore != "" {
return true
}
if f.CreatedAfter != "" {
return true
}
if f.UpdatedBefore != "" {
return true
}
if f.UpdatedAfter != "" {
return true
}
if f.Text != "" {
return true
}
if f.Name != "" {
return true
}
if f.NameGiven != "" {
return true
}
if f.NameSurname != "" {
return true
}
if f.NameSurname2 != "" {
return true
}
if f.NickName != "" {
return true
}
if f.Organization != "" {
return true
}
if f.Email != "" {
return true
}
if f.Phone != "" {
return true
}
if f.OnlineService != "" {
return true
}
if f.Address != "" {
return true
}
if f.Note != "" {
return true
}
return false
}
var _ ContactCardFilterElement = &ContactCardFilterCondition{}
type ContactCardFilterOperator struct {
Operator FilterOperatorTerm `json:"operator"`
Conditions []ContactCardFilterElement `json:"conditions,omitempty"`
}
func (o ContactCardFilterOperator) _isAContactCardFilterElement() {
}
func (o ContactCardFilterOperator) IsNotEmpty() bool {
return len(o.Conditions) > 0
}
var _ ContactCardFilterElement = &ContactCardFilterOperator{}
type ContactCardQueryCommand struct {
AccountId string `json:"accountId"`
Filter ContactCardFilterElement `json:"filter,omitempty"`
Sort []ContactCardComparator `json:"sort,omitempty"`
// The zero-based index of the first id in the full list of results to return.
//
// If a negative value is given, it is an offset from the end of the list.
// Specifically, the negative value MUST be added to the total number of results given
// the filter, and if still negative, its clamped to 0. This is now the zero-based
// index of the first id to return.
//
// If the index is greater than or equal to the total number of objects in the results
// list, then the ids array in the response will be empty, but this is not an error.
Position uint `json:"position,omitempty"`
// An Email id.
//
// If supplied, the position argument is ignored.
// The index of this id in the results will be used in combination with the anchorOffset
// argument to determine the index of the first result to return.
Anchor string `json:"anchor,omitempty"`
// The index of the first result to return relative to the index of the anchor,
// if an anchor is given.
//
// Default: 0.
//
// This MAY be negative.
//
// For example, -1 means the Email immediately preceding the anchor is the first result in
// the list returned.
AnchorOffset int `json:"anchorOffset,omitzero"`
// The maximum number of results to return.
//
// If null, no limit presumed.
// The server MAY choose to enforce a maximum limit argument.
// In this case, if a greater value is given (or if it is null), the limit is clamped
// to the maximum; the new limit is returned with the response so the client is aware.
//
// If a negative value is given, the call MUST be rejected with an invalidArguments error.
Limit uint `json:"limit,omitempty"`
// Does the client wish to know the total number of results in the query?
//
// This may be slow and expensive for servers to calculate, particularly with complex filters,
// so clients should take care to only request the total when needed.
CalculateTotal bool `json:"calculateTotal,omitempty"`
}
type ContactCardQueryResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A string encoding the current state of the query on the server.
//
// This string MUST change if the results of the query (i.e., the matching ids and their sort order) have changed.
// The queryState string MAY change if something has changed on the server, which means the results may have changed
// but the server doesnt know for sure.
//
// The queryState string only represents the ordered list of ids that match the particular query (including its sort/filter).
// There is no requirement for it to change if a property on an object matching the query changes but the query results are unaffected
// (indeed, it is more efficient if the queryState string does not change in this case).
//
// The queryState string only has meaning when compared to future responses to a query with the same type/sort/filter or when used with
// /queryChanges to fetch changes.
//
// Should a client receive back a response with a different queryState string to a previous call, it MUST either throw away the currently
// cached query and fetch it again (note, this does not require fetching the records again, just the list of ids) or call
// Email/queryChanges to get the difference.
QueryState State `json:"queryState"`
// This is true if the server supports calling ContactCard/queryChanges with these filter/sort parameters.
//
// Note, this does not guarantee that the ContactCard/queryChanges call will succeed, as it may only be possible for a limited time
// afterwards due to server internal implementation details.
CanCalculateChanges bool `json:"canCalculateChanges"`
// The zero-based index of the first result in the ids array within the complete list of query results.
Position uint `json:"position"`
// The list of ids for each ContactCard in the query results, starting at the index given by the position argument of this
// response and continuing until it hits the end of the results or reaches the limit number of ids.
//
// If position is >= total, this MUST be the empty list.
Ids []string `json:"ids"`
// The total number of ContactCards in the results (given the filter).
//
// Only if requested.
//
// This argument MUST be omitted if the calculateTotal request argument is not true.
Total uint `json:"total,omitempty,omitzero"`
// The limit enforced by the server on the maximum number of results to return (if set by the server).
//
// This is only returned if the server set a limit or used a different limit than that given in the request.
Limit uint `json:"limit,omitempty,omitzero"`
}
type ContactCardGetCommand struct {
// The ids of the ContactCard objects to return.
//
// If null, then all records of the data type are returned, if this is supported for that
// data type and the number of records does not exceed the maxObjectsInGet limit.
Ids []string `json:"ids,omitempty"`
// The id of the account to use.
AccountId string `json:"accountId"`
// If supplied, only the properties listed in the array are returned for each ContactCard object.
//
// The id property of the object is always returned, even if not explicitly requested.
//
// If an invalid property is requested, the call MUST be rejected with an invalidArguments error.
Properties []string `json:"properties,omitempty"`
}
type ContactCardGetRefCommand struct {
// The ids of the ContactCard objects to return.
//
// If null, then all records of the data type are returned, if this is supported for that
// data type and the number of records does not exceed the maxObjectsInGet limit.
IdsRef *ResultReference `json:"#ids,omitempty"`
// The id of the account to use.
AccountId string `json:"accountId"`
// If supplied, only the properties listed in the array are returned for each ContactCard object.
//
// The id property of the object is always returned, even if not explicitly requested.
//
// If an invalid property is requested, the call MUST be rejected with an invalidArguments error.
Properties []string `json:"properties,omitempty"`
}
type ContactCardGetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A (preferably short) string representing the state on the server for all the data of this type
// in the account (not just the objects returned in this call).
//
// If the data changes, this string MUST change.
// If the Email data is unchanged, servers SHOULD return the same state string on subsequent requests for this data type.
State State `json:"state"`
// An array of the ContactCard objects requested.
//
// This is the empty array if no objects were found or if the ids argument passed in was also an empty array.
//
// The results MAY be in a different order to the ids in the request arguments.
//
// If an identical id is included more than once in the request, the server MUST only include it once in either
// the list or the notFound argument of the response.
List []jscontact.ContactCard `json:"list"`
// This array contains the ids passed to the method for records that do not exist.
//
// The array is empty if all requested ids were found or if the ids argument passed in was either null or an empty array.
NotFound []any `json:"notFound"`
}
type ContactCardUpdate map[string]any
type ContactCardSetCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// This is a state string as returned by the `ContactCard/get` method.
//
// If supplied, the string must match the current state; otherwise, the method will be aborted and a
// `stateMismatch` error returned.
//
// If null, any changes will be applied to the current state.
IfInState string `json:"ifInState,omitempty"`
// A map of a creation id (a temporary id set by the client) to ContactCard objects,
// or null if no objects are to be created.
//
// The ContactCard object type definition may define default values for properties.
//
// Any such property may be omitted by the client.
//
// The client MUST omit any properties that may only be set by the server.
Create map[string]jscontact.ContactCard `json:"create,omitempty"`
// A map of an id to a `Patch` object to apply to the current Email object with that id,
// or null if no objects are to be updated.
//
// A `PatchObject` is of type `String[*]` and represents an unordered set of patches.
//
// The keys are a path in JSON Pointer Format [@!RFC6901], with an implicit leading `/` (i.e., prefix each key
// with `/` before applying the JSON Pointer evaluation algorithm).
//
// All paths MUST also conform to the following restrictions; if there is any violation, the update
// MUST be rejected with an `invalidPatch` error:
// !- The pointer MUST NOT reference inside an array (i.e., you MUST NOT insert/delete from an array; the array MUST be replaced in its entirety instead).
// !- All parts prior to the last (i.e., the value after the final slash) MUST already exist on the object being patched.
// !- There MUST NOT be two patches in the `PatchObject` where the pointer of one is the prefix of the pointer of the other, e.g., `"alerts/1/offset"` and `"alerts"`.
//
// The value associated with each pointer determines how to apply that patch:
// !- If null, set to the default value if specified for this property; otherwise, remove the property from the patched object. If the key is not present in the parent, this a no-op.
// !- Anything else: The value to set for this property (this may be a replacement or addition to the object being patched).
//
// Any server-set properties MAY be included in the patch if their value is identical to the current server value
// (before applying the patches to the object). Otherwise, the update MUST be rejected with an `invalidProperties` `SetError`.
//
// This patch definition is designed such that an entire Email object is also a valid `PatchObject`.
//
// The client may choose to optimise network usage by just sending the diff or may send the whole object; the server
// processes it the same either way.
Update map[string]ContactCardUpdate `json:"update,omitempty"`
// A list of ids for ContactCard objects to permanently delete, or null if no objects are to be destroyed.
Destroy []string `json:"destroy,omitempty"`
}
type ContactCardSetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// The state string that would have been returned by ContactCard/get before making the
// requested changes, or null if the server doesnt know what the previous state
// string was.
OldState State `json:"oldState,omitempty"`
// The state string that will now be returned by Email/get.
NewState State `json:"newState"`
// A map of the creation id to an object containing any properties of the created Email object
// that were not sent by the client.
//
// This includes all server-set properties (such as the id in most object types) and any properties
// that were omitted by the client and thus set to a default by the server.
//
// This argument is null if no ContactCard objects were successfully created.
Created map[string]*jscontact.ContactCard `json:"created,omitempty"`
// The keys in this map are the ids of all Emails that were successfully updated.
//
// The value for each id is an ContactCard object containing any property that changed in a way not
// explicitly requested by the PatchObject sent to the server, or null if none.
//
// This lets the client know of any changes to server-set or computed properties.
//
// This argument is null if no ContactCard objects were successfully updated.
Updated map[string]*jscontact.ContactCard `json:"updated,omitempty"`
// A list of ContactCard ids for records that were successfully destroyed, or null if none.
Destroyed []string `json:"destroyed,omitempty"`
// A map of the creation id to a SetError object for each record that failed to be created,
// or null if all successful.
NotCreated map[string]SetError `json:"notCreated,omitempty"`
// A map of the ContactCard id to a SetError object for each record that failed to be updated,
// or null if all successful.
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
// A map of the ContactCard id to a SetError object for each record that failed to be destroyed,
// or null if all successful.
NotDestroyed map[string]SetError `json:"notDestroyed,omitempty"`
}
type CalendarEventParseCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// The ids of the blobs to parse
BlobIds []string `json:"blobIds,omitempty"`
// If supplied, only the properties listed in the array are returned for each CalendarEvent object.
//
// If omitted, defaults to all the properties.
Properties []string `json:"properties,omitempty"`
}
type CalendarEventParseResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A map of blob ids to parsed CalendarEvent objects representations for each successfully
// parsed blob, or null if none.
Parsed map[string][]CalendarEvent `json:"parsed,omitempty"`
// A list of blob ids given that could not be found, or null if none.
NotFound []string `json:"notFound,omitempty"`
// A list of blob ids given that corresponded to blobs that could not be parsed as
// CalendarEvents, or null if none.
NotParsable []string `json:"notParsable,omitempty"`
}
type CalendarGetCommand struct {
AccountId string `json:"accountId"`
Ids []string `json:"ids,omitempty"`
}
type CalendarGetResponse struct {
AccountId string `json:"accountId"`
State State `json:"state,omitempty"`
List []Calendar `json:"list,omitempty"`
NotFound []string `json:"notFound,omitempty"`
}
type CalendarEventComparator struct {
// The name of the property on the objects to compare.
Property string `json:"property,omitempty"`
// If true, sort in ascending order.
//
// Optional; default value: true.
//
// If false, reverse the comparators results to sort in descending order.
IsAscending bool `json:"isAscending,omitempty"`
// The identifier, as registered in the collation registry defined in [RFC4790],
// for the algorithm to use when comparing the order of strings.
//
// Optional; default is server dependent.
//
// The algorithms the server supports are advertised in the capabilities object returned
// with the Session object.
//
// [RFC4790]: https://www.rfc-editor.org/rfc/rfc4790.html
Collation string `json:"collation,omitempty"`
// CalendarEvent-specific: If true, the server will expand any recurring event.
//
// If true, the filter MUST be just a FilterCondition (not a FilterOperator) and MUST include both
// a “before” and “after” property. This ensures the server is not asked to return an infinite number of results.
// default: false
ExpandRecurrences bool `json:"expandRecurrences,omitzero"`
// CalendarEvent-specific: The time zone for before/after filter conditions.
// default: “Etc/UTC”
TimeZone string `json:"timeZone,omitempty"`
}
type CalendarEventFilterElement interface {
_isACalendarEventFilterElement() // marker method
IsNotEmpty() bool
}
type CalendarEventFilterCondition struct {
// A calendar id.
// An event must be in this calendar to match the condition.
InCalendar string `json:"inCalendar,omitempty"`
// The end of the event, or any recurrence of the event, in the time zone given as
// the timeZone argument, must be after this date to match the condition.
After LocalDate `json:"after,omitzero"`
// The start of the event, or any recurrence of the event, in the time zone given
// as the timeZone argument, must be before this date to match the condition.
Before LocalDate `json:"before,omitzero"`
// Looks for the text in the title, description, locations (matching name/description),
// participants (matching name/email) and any other textual properties of the event
// or any recurrence of the event.
Text string `json:"text,omitempty"`
// Looks for the text in the title property of the event, or the overridden title
// property of a recurrence.
Title string `json:"title,omitempty"`
// Looks for the text in the description property of the event, or the overridden
// description property of a recurrence.
Description string `json:"description,omitempty"`
// Looks for the text in the locations property of the event (matching name/description
// of a location), or the overridden locations property of a recurrence.
Location string `json:"location,omitempty"`
// Looks for the text in the name or email fields of a participant in the participants
// property of the event, or the overridden participants property of a recurrence,
// where the participant has a role of “owner”.
Owner string `json:"owner,omitempty"`
// Looks for the text in the name or email fields of a participant in the participants
// property of the event, or the overridden participants property of a recurrence,
// where the participant has a role of “attendee”.
Attendee string `json:"attendee,omitempty"`
// Must match. If owner/attendee condition, status must be of that participant. Otherwise any.
ParticipationStatus string `json:"participationStatus,omitempty"`
// The uid of the event is exactly the given string.
Uid string `json:"uid,omitempty"`
}
func (f CalendarEventFilterCondition) _isACalendarEventFilterElement() {
}
func (f CalendarEventFilterCondition) IsNotEmpty() bool {
if f.InCalendar != "" {
return true
}
if f.After != "" {
return true
}
if f.Before != "" {
return true
}
if f.Text != "" {
return true
}
if f.Title != "" {
return true
}
if f.Description != "" {
return true
}
if f.Location != "" {
return true
}
if f.Owner != "" {
return true
}
if f.Attendee != "" {
return true
}
if f.ParticipationStatus != "" {
return true
}
if f.Uid != "" {
return true
}
return false
}
var _ CalendarEventFilterElement = &CalendarEventFilterCondition{}
type CalendarEventFilterOperator struct {
Operator FilterOperatorTerm `json:"operator"`
Conditions []CalendarEventFilterElement `json:"conditions,omitempty"`
}
func (o CalendarEventFilterOperator) _isACalendarEventFilterElement() {
}
func (o CalendarEventFilterOperator) IsNotEmpty() bool {
return len(o.Conditions) > 0
}
var _ CalendarEventFilterElement = &CalendarEventFilterOperator{}
type CalendarEventQueryCommand struct {
AccountId string `json:"accountId"`
Filter CalendarEventFilterElement `json:"filter,omitempty"`
Sort []CalendarEventComparator `json:"sort,omitempty"`
// The zero-based index of the first id in the full list of results to return.
//
// If a negative value is given, it is an offset from the end of the list.
// Specifically, the negative value MUST be added to the total number of results given
// the filter, and if still negative, its clamped to 0. This is now the zero-based
// index of the first id to return.
//
// If the index is greater than or equal to the total number of objects in the results
// list, then the ids array in the response will be empty, but this is not an error.
Position uint `json:"position,omitempty"`
// An Email id.
//
// If supplied, the position argument is ignored.
// The index of this id in the results will be used in combination with the anchorOffset
// argument to determine the index of the first result to return.
Anchor string `json:"anchor,omitempty"`
// The index of the first result to return relative to the index of the anchor,
// if an anchor is given.
//
// Default: 0.
//
// This MAY be negative.
//
// For example, -1 means the Email immediately preceding the anchor is the first result in
// the list returned.
AnchorOffset int `json:"anchorOffset,omitzero"`
// The maximum number of results to return.
//
// If null, no limit presumed.
// The server MAY choose to enforce a maximum limit argument.
// In this case, if a greater value is given (or if it is null), the limit is clamped
// to the maximum; the new limit is returned with the response so the client is aware.
//
// If a negative value is given, the call MUST be rejected with an invalidArguments error.
Limit uint `json:"limit,omitempty"`
// Does the client wish to know the total number of results in the query?
//
// This may be slow and expensive for servers to calculate, particularly with complex filters,
// so clients should take care to only request the total when needed.
CalculateTotal bool `json:"calculateTotal,omitempty"`
}
type CalendarEventQueryResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A string encoding the current state of the query on the server.
//
// This string MUST change if the results of the query (i.e., the matching ids and their sort order) have changed.
// The queryState string MAY change if something has changed on the server, which means the results may have changed
// but the server doesnt know for sure.
//
// The queryState string only represents the ordered list of ids that match the particular query (including its sort/filter).
// There is no requirement for it to change if a property on an object matching the query changes but the query results are unaffected
// (indeed, it is more efficient if the queryState string does not change in this case).
//
// The queryState string only has meaning when compared to future responses to a query with the same type/sort/filter or when used with
// /queryChanges to fetch changes.
//
// Should a client receive back a response with a different queryState string to a previous call, it MUST either throw away the currently
// cached query and fetch it again (note, this does not require fetching the records again, just the list of ids) or call
// CalendarEvent/queryChanges to get the difference.
QueryState State `json:"queryState"`
// This is true if the server supports calling CalendarEvent/queryChanges with these filter/sort parameters.
//
// Note, this does not guarantee that the CalendarEvent/queryChanges call will succeed, as it may only be possible for a limited time
// afterwards due to server internal implementation details.
CanCalculateChanges bool `json:"canCalculateChanges"`
// The zero-based index of the first result in the ids array within the complete list of query results.
Position uint `json:"position"`
// The list of ids for each ContactCard in the query results, starting at the index given by the position argument of this
// response and continuing until it hits the end of the results or reaches the limit number of ids.
//
// If position is >= total, this MUST be the empty list.
Ids []string `json:"ids"`
// The total number of CalendarEvents in the results (given the filter).
//
// Only if requested.
//
// This argument MUST be omitted if the calculateTotal request argument is not true.
Total uint `json:"total,omitempty,omitzero"`
// The limit enforced by the server on the maximum number of results to return (if set by the server).
//
// This is only returned if the server set a limit or used a different limit than that given in the request.
Limit uint `json:"limit,omitempty,omitzero"`
}
type CalendarEventGetCommand struct {
// The ids of the CalendarEvent objects to return.
//
// If null, then all records of the data type are returned, if this is supported for that
// data type and the number of records does not exceed the maxObjectsInGet limit.
Ids []string `json:"ids,omitempty"`
// The id of the account to use.
AccountId string `json:"accountId"`
// If supplied, only the properties listed in the array are returned for each CalendarEvent object.
//
// The id property of the object is always returned, even if not explicitly requested.
//
// If an invalid property is requested, the call MUST be rejected with an invalidArguments error.
Properties []string `json:"properties,omitempty"`
}
type CalendarEventGetRefCommand struct {
// The ids of the CalendarEvent objects to return.
//
// If null, then all records of the data type are returned, if this is supported for that
// data type and the number of records does not exceed the maxObjectsInGet limit.
IdsRef *ResultReference `json:"#ids,omitempty"`
// The id of the account to use.
AccountId string `json:"accountId"`
// If supplied, only the properties listed in the array are returned for each CalendarEvent object.
//
// The id property of the object is always returned, even if not explicitly requested.
//
// If an invalid property is requested, the call MUST be rejected with an invalidArguments error.
Properties []string `json:"properties,omitempty"`
}
type CalendarEventGetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// A (preferably short) string representing the state on the server for all the data of this type
// in the account (not just the objects returned in this call).
//
// If the data changes, this string MUST change.
// If the Email data is unchanged, servers SHOULD return the same state string on subsequent requests for this data type.
State State `json:"state"`
// An array of the CalendarEvent objects requested.
//
// This is the empty array if no objects were found or if the ids argument passed in was also an empty array.
//
// The results MAY be in a different order to the ids in the request arguments.
//
// If an identical id is included more than once in the request, the server MUST only include it once in either
// the list or the notFound argument of the response.
List []CalendarEvent `json:"list"`
// This array contains the ids passed to the method for records that do not exist.
//
// The array is empty if all requested ids were found or if the ids argument passed in was either null or an empty array.
NotFound []any `json:"notFound"`
}
type CalendarEventUpdate map[string]any
type CalendarEventSetCommand struct {
// The id of the account to use.
AccountId string `json:"accountId"`
// This is a state string as returned by the `CalendarEvent/get` method.
//
// If supplied, the string must match the current state; otherwise, the method will be aborted and a
// `stateMismatch` error returned.
//
// If null, any changes will be applied to the current state.
IfInState string `json:"ifInState,omitempty"`
// A map of a creation id (a temporary id set by the client) to CalendarEvent objects,
// or null if no objects are to be created.
//
// The CalendarEvent object type definition may define default values for properties.
//
// Any such property may be omitted by the client.
//
// The client MUST omit any properties that may only be set by the server.
Create map[string]CalendarEvent `json:"create,omitempty"`
// A map of an id to a `Patch` object to apply to the current Email object with that id,
// or null if no objects are to be updated.
//
// A `PatchObject` is of type `String[*]` and represents an unordered set of patches.
//
// The keys are a path in JSON Pointer Format [@!RFC6901], with an implicit leading `/` (i.e., prefix each key
// with `/` before applying the JSON Pointer evaluation algorithm).
//
// All paths MUST also conform to the following restrictions; if there is any violation, the update
// MUST be rejected with an `invalidPatch` error:
// !- The pointer MUST NOT reference inside an array (i.e., you MUST NOT insert/delete from an array; the array MUST be replaced in its entirety instead).
// !- All parts prior to the last (i.e., the value after the final slash) MUST already exist on the object being patched.
// !- There MUST NOT be two patches in the `PatchObject` where the pointer of one is the prefix of the pointer of the other, e.g., `"alerts/1/offset"` and `"alerts"`.
//
// The value associated with each pointer determines how to apply that patch:
// !- If null, set to the default value if specified for this property; otherwise, remove the property from the patched object. If the key is not present in the parent, this a no-op.
// !- Anything else: The value to set for this property (this may be a replacement or addition to the object being patched).
//
// Any server-set properties MAY be included in the patch if their value is identical to the current server value
// (before applying the patches to the object). Otherwise, the update MUST be rejected with an `invalidProperties` `SetError`.
//
// This patch definition is designed such that an entire Email object is also a valid `PatchObject`.
//
// The client may choose to optimise network usage by just sending the diff or may send the whole object; the server
// processes it the same either way.
Update map[string]CalendarEventUpdate `json:"update,omitempty"`
// A list of ids for CalendarEvent objects to permanently delete, or null if no objects are to be destroyed.
Destroy []string `json:"destroy,omitempty"`
}
type CalendarEventSetResponse struct {
// The id of the account used for the call.
AccountId string `json:"accountId"`
// The state string that would have been returned by CalendarEvent/get before making the
// requested changes, or null if the server doesnt know what the previous state
// string was.
OldState State `json:"oldState,omitempty"`
// The state string that will now be returned by Email/get.
NewState State `json:"newState"`
// A map of the creation id to an object containing any properties of the created Email object
// that were not sent by the client.
//
// This includes all server-set properties (such as the id in most object types) and any properties
// that were omitted by the client and thus set to a default by the server.
//
// This argument is null if no CalendarEvent objects were successfully created.
Created map[string]*CalendarEvent `json:"created,omitempty"`
// The keys in this map are the ids of all CalendarEvents that were successfully updated.
//
// The value for each id is an CalendarEvent object containing any property that changed in a way not
// explicitly requested by the PatchObject sent to the server, or null if none.
//
// This lets the client know of any changes to server-set or computed properties.
//
// This argument is null if no CalendarEvent objects were successfully updated.
Updated map[string]*CalendarEvent `json:"updated,omitempty"`
// A list of CalendarEvent ids for records that were successfully destroyed, or null if none.
Destroyed []string `json:"destroyed,omitempty"`
// A map of the creation id to a SetError object for each record that failed to be created,
// or null if all successful.
NotCreated map[string]SetError `json:"notCreated,omitempty"`
// A map of the ContactCard id to a SetError object for each record that failed to be updated,
// or null if all successful.
NotUpdated map[string]SetError `json:"notUpdated,omitempty"`
// A map of the CalendarEvent id to a SetError object for each record that failed to be destroyed,
// or null if all successful.
NotDestroyed map[string]SetError `json:"notDestroyed,omitempty"`
}
type ErrorResponse struct {
Type string `json:"type"`
Description string `json:"description,omitempty"`
}
const (
ErrorCommand Command = "error" // only occurs in responses
CommandBlobGet Command = "Blob/get"
CommandBlobUpload Command = "Blob/upload"
CommandEmailGet Command = "Email/get"
CommandEmailQuery Command = "Email/query"
CommandEmailChanges Command = "Email/changes"
CommandEmailSet Command = "Email/set"
CommandEmailImport Command = "Email/import"
CommandEmailSubmissionGet Command = "EmailSubmission/get"
CommandEmailSubmissionSet Command = "EmailSubmission/set"
CommandThreadGet Command = "Thread/get"
CommandMailboxGet Command = "Mailbox/get"
CommandMailboxSet Command = "Mailbox/set"
CommandMailboxQuery Command = "Mailbox/query"
CommandMailboxChanges Command = "Mailbox/changes"
CommandIdentityGet Command = "Identity/get"
CommandIdentitySet Command = "Identity/set"
CommandVacationResponseGet Command = "VacationResponse/get"
CommandVacationResponseSet Command = "VacationResponse/set"
CommandSearchSnippetGet Command = "SearchSnippet/get"
CommandQuotaGet Command = "Quota/get"
CommandAddressBookGet Command = "AddressBook/get"
CommandContactCardQuery Command = "ContactCard/query"
CommandContactCardGet Command = "ContactCard/get"
CommandContactCardSet Command = "ContactCard/set"
CommandCalendarEventParse Command = "CalendarEvent/parse"
CommandCalendarGet Command = "Calendar/get"
CommandCalendarEventQuery Command = "CalendarEvent/query"
CommandCalendarEventGet Command = "CalendarEvent/get"
CommandCalendarEventSet Command = "CalendarEvent/set"
)
var CommandResponseTypeMap = map[Command]func() any{
ErrorCommand: func() any { return ErrorResponse{} },
CommandBlobGet: func() any { return BlobGetResponse{} },
CommandBlobUpload: func() any { return BlobUploadResponse{} },
CommandMailboxQuery: func() any { return MailboxQueryResponse{} },
CommandMailboxGet: func() any { return MailboxGetResponse{} },
CommandMailboxSet: func() any { return MailboxSetResponse{} },
CommandMailboxChanges: func() any { return MailboxChangesResponse{} },
CommandEmailQuery: func() any { return EmailQueryResponse{} },
CommandEmailChanges: func() any { return EmailChangesResponse{} },
CommandEmailGet: func() any { return EmailGetResponse{} },
CommandEmailSet: func() any { return EmailSetResponse{} },
CommandEmailSubmissionGet: func() any { return EmailSubmissionGetResponse{} },
CommandEmailSubmissionSet: func() any { return EmailSubmissionSetResponse{} },
CommandThreadGet: func() any { return ThreadGetResponse{} },
CommandIdentityGet: func() any { return IdentityGetResponse{} },
CommandIdentitySet: func() any { return IdentitySetResponse{} },
CommandVacationResponseGet: func() any { return VacationResponseGetResponse{} },
CommandVacationResponseSet: func() any { return VacationResponseSetResponse{} },
CommandSearchSnippetGet: func() any { return SearchSnippetGetResponse{} },
CommandQuotaGet: func() any { return QuotaGetResponse{} },
CommandAddressBookGet: func() any { return AddressBookGetResponse{} },
CommandContactCardQuery: func() any { return ContactCardQueryResponse{} },
CommandContactCardGet: func() any { return ContactCardGetResponse{} },
CommandContactCardSet: func() any { return ContactCardSetResponse{} },
CommandCalendarEventParse: func() any { return CalendarEventParseResponse{} },
CommandCalendarGet: func() any { return CalendarGetResponse{} },
CommandCalendarEventQuery: func() any { return CalendarEventQueryResponse{} },
CommandCalendarEventGet: func() any { return CalendarEventGetResponse{} },
CommandCalendarEventSet: func() any { return CalendarEventSetResponse{} },
}