export interface EmailHeader { name: string; value: string; } export interface Email { id: string; threadId: string; /** Owning JMAP account for non-primary results; absent = primary account. */ accountId?: string; mailboxIds: Record; keywords: Record; size: number; receivedAt: string; from?: EmailAddress[]; to?: EmailAddress[]; cc?: EmailAddress[]; bcc?: EmailAddress[]; replyTo?: EmailAddress[]; subject?: string; sentAt?: string; preview?: string; textBody?: EmailBodyPart[]; htmlBody?: EmailBodyPart[]; bodyValues?: Record; attachments?: Attachment[]; hasAttachment: boolean; // Extended header information messageId?: string; inReplyTo?: string[]; references?: string[]; headers?: Record; // Security headers parsed authenticationResults?: AuthenticationResults; spamScore?: number; spamStatus?: string; spamLLM?: { verdict: string; explanation: string; }; } export interface AuthenticationResults { spf?: { result: 'pass' | 'fail' | 'softfail' | 'neutral' | 'none' | 'temperror' | 'permerror'; domain?: string; ip?: string; }; dkim?: { result: 'pass' | 'fail' | 'policy' | 'neutral' | 'temperror' | 'permerror'; domain?: string; selector?: string; }; dmarc?: { result: 'pass' | 'fail' | 'none'; policy?: 'reject' | 'quarantine' | 'none'; domain?: string; }; iprev?: { result: 'pass' | 'fail'; ip?: string; }; } export interface EmailBodyValue { value: string; isEncodingProblem?: boolean; isTruncated?: boolean; } export interface EmailAddress { name?: string; email: string; } export interface EmailBodyPart { partId: string; blobId: string; size: number; name?: string; type: string; charset?: string; disposition?: string; cid?: string; language?: string[]; location?: string; subParts?: EmailBodyPart[]; } export interface Attachment { partId: string; blobId: string; size: number; name?: string; type: string; charset?: string; cid?: string; disposition?: string; } export interface Mailbox { id: string; originalId?: string; // Original JMAP ID (for shared mailboxes) name: string; parentId?: string; role?: string; sortOrder: number; totalEmails: number; unreadEmails: number; totalThreads: number; unreadThreads: number; myRights: { mayReadItems: boolean; mayAddItems: boolean; mayRemoveItems: boolean; maySetSeen: boolean; maySetKeywords: boolean; mayCreateChild: boolean; mayRename: boolean; mayDelete: boolean; maySubmit: boolean; }; isSubscribed: boolean; // Shared folder support accountId?: string; accountName?: string; isShared?: boolean; } export interface Thread { id: string; emailIds: string[]; } // Thread grouping for UI display export interface ThreadGroup { threadId: string; emails: Email[]; // Emails in this thread (sorted by receivedAt desc) latestEmail: Email; // Most recent email participantNames: string[];// Unique participant names hasUnread: boolean; // Any unread emails in thread hasStarred: boolean; // Any starred emails in thread hasAttachment: boolean; // Any email has attachment emailCount: number; // Total emails in thread } export interface Identity { id: string; name: string; email: string; replyTo?: EmailAddress[]; bcc?: EmailAddress[]; textSignature?: string; htmlSignature?: string; mayDelete: boolean; } // RFC 9553 JSContact / RFC 9610 JMAP for Contacts export interface ContactCard { id: string; uid?: string; addressBookIds: Record; kind?: 'individual' | 'group' | 'org'; name?: ContactName; emails?: Record; phones?: Record; organizations?: Record; addresses?: Record; nicknames?: Record; notes?: Record; members?: Record; created?: string; updated?: string; } export interface ContactName { components: NameComponent[]; isOrdered?: boolean; } export interface NameComponent { kind: 'given' | 'surname' | 'prefix' | 'suffix' | 'additional'; value: string; } export interface ContactEmail { address: string; contexts?: Record; label?: string; } export interface ContactPhone { number: string; contexts?: Record; label?: string; } export interface ContactOrganization { name?: string; units?: Array<{ name: string }>; } export interface ContactAddress { street?: string; locality?: string; region?: string; postcode?: string; country?: string; contexts?: Record; label?: string; } export interface ContactNickname { name: string; } export interface ContactNote { note: string; } export interface AddressBook { id: string; name: string; description?: string | null; sortOrder?: number; isDefault?: boolean; isSubscribed?: boolean; myRights?: AddressBookRights; } export interface AddressBookRights { mayRead: boolean; mayWrite: boolean; mayShare: boolean; mayDelete: boolean; } export interface VacationResponse { id: string; isEnabled: boolean; fromDate: string | null; toDate: string | null; subject: string; textBody: string; htmlBody: string | null; } export interface EmailSubmission { id: string; identityId: string; emailId: string; threadId?: string; envelope: { mailFrom: EmailAddress; rcptTo: EmailAddress[]; }; sendAt?: string; undoStatus: "pending" | "final" | "canceled"; deliveryStatus?: Record; dsnBlobIds?: string[]; mdnBlobIds?: string[]; } export interface DeliveryStatus { smtpReply: string; delivered: "queued" | "yes" | "no" | "unknown"; displayed: "unknown" | "yes"; } // JMAP Calendar Types (RFC 8984 JSCalendar + RFC 9553 JMAP Calendars) export interface Calendar { id: string; name: string; description: string | null; color: string | null; sortOrder: number; isSubscribed: boolean; isVisible: boolean; isDefault: boolean; includeInAvailability: 'all' | 'attending' | 'none'; defaultAlertsWithTime: Record | null; defaultAlertsWithoutTime: Record | null; timeZone: string | null; shareWith: Record | null; myRights: CalendarRights; } export interface CalendarRights { mayReadFreeBusy: boolean; mayReadItems: boolean; mayWriteAll: boolean; mayWriteOwn: boolean; mayUpdatePrivate: boolean; mayRSVP: boolean; mayAdmin: boolean; mayDelete: boolean; } export interface CalendarEvent { id: string; calendarIds: Record; isDraft: boolean; isOrigin: boolean; utcStart: string | null; utcEnd: string | null; '@type': 'Event'; uid: string; title: string; description: string; descriptionContentType: string; created: string | null; updated: string; sequence: number; start: string; duration?: string; timeZone: string | null; showWithoutTime: boolean; status: 'tentative' | 'confirmed' | 'cancelled'; freeBusyStatus: 'free' | 'busy'; privacy: 'public' | 'private' | 'secret'; color: string | null; keywords: Record | null; categories: Record | null; locale: string | null; replyTo: Record | null; participants: Record | null; mayInviteSelf: boolean; mayInviteOthers: boolean; hideAttendees: boolean; recurrenceId: string | null; recurrenceIdTimeZone: string | null; recurrenceRules: CalendarRecurrenceRule[] | null; recurrenceOverrides: Record> | null; excludedRecurrenceRules: CalendarRecurrenceRule[] | null; useDefaultAlerts: boolean; alerts: Record | null; locations: Record | null; virtualLocations: Record | null; links: Record | null; relatedTo: Record | null; organizerCalendarAddress?: string | null; } export interface CalendarParticipant { '@type': 'Participant'; name: string; email?: string; calendarAddress?: string | null; description: string | null; sendTo: Record | null; kind: 'individual' | 'group' | 'location' | 'resource'; roles: Record; participationStatus: 'accepted' | 'declined' | 'tentative' | 'delegated' | 'needs-action'; participationComment: string | null; expectReply: boolean; scheduleAgent: 'server' | 'client' | 'none'; scheduleForceSend: boolean; scheduleId: string | null; scheduleSequence: number; scheduleStatus: string[] | null; scheduleUpdated: string | null; invitedBy: string | null; delegatedTo: Record | null; delegatedFrom: Record | null; memberOf: Record | null; locationId: string | null; language: string | null; links: Record | null; } export interface CalendarRecurrenceRule { '@type': 'RecurrenceRule'; frequency: 'yearly' | 'monthly' | 'weekly' | 'daily' | 'hourly' | 'minutely' | 'secondly'; interval: number; rscale: string; skip: 'omit' | 'backward' | 'forward'; firstDayOfWeek: 'mo' | 'tu' | 'we' | 'th' | 'fr' | 'sa' | 'su'; byDay: CalendarNDay[] | null; byMonthDay: number[] | null; byMonth: string[] | null; byYearDay: number[] | null; byWeekNo: number[] | null; byHour: number[] | null; byMinute: number[] | null; bySecond: number[] | null; bySetPosition: number[] | null; count: number | null; until: string | null; } export interface CalendarNDay { day: string; nthOfPeriod?: number; } export interface CalendarEventAlert { '@type': 'Alert'; trigger: CalendarOffsetTrigger | CalendarAbsoluteTrigger; action: 'display' | 'email'; acknowledged: string | null; relatedTo: Record | null; } export interface CalendarOffsetTrigger { '@type': 'OffsetTrigger'; offset: string; relativeTo: 'start' | 'end'; } export interface CalendarAbsoluteTrigger { '@type': 'AbsoluteTrigger'; when: string; } export interface CalendarLocation { '@type': 'Location'; name: string; description: string | null; locationTypes: Record | null; coordinates: string | null; timeZone: string | null; links: Record | null; relativeTo: 'start' | 'end' | null; } export interface CalendarVirtualLocation { '@type': 'VirtualLocation'; name: string | null; description: string | null; uri: string; features: Record | null; } export interface CalendarLink { '@type': 'Link'; href: string; cid: string | null; contentType: string | null; size: number | null; rel: string | null; display: string | null; title: string | null; } export interface CalendarRelation { '@type': 'Relation'; relation: Record | null; } export interface CalendarParticipantIdentity { id: string; name: string; scheduleId: string; sendTo: Record; isDefault: boolean; } export interface CalendarEventNotification { id: string; created: string; changedBy: { name: string; email: string; principalId: string | null; scheduleId: string | null; }; comment: string | null; type: 'created' | 'updated' | 'destroyed'; calendarEventId: string; isDraft: boolean; event?: CalendarEvent; eventPatch?: Record; } export interface CalendarEventFilter { inCalendars?: string[]; after?: string; before?: string; text?: string; title?: string; description?: string; location?: string; owner?: string; attendee?: string; participationStatus?: string; uid?: string; } // JMAP Push Notification Types (RFC 8620 Section 7) export interface StateChange { '@type': 'StateChange'; changed: { [accountId: string]: { Email?: string; Mailbox?: string; Thread?: string; EmailDelivery?: string; EmailSubmission?: string; Identity?: string; ContactCard?: string; AddressBook?: string; Calendar?: string; CalendarEvent?: string; SieveScript?: string; }; }; } export interface PushSubscription { id: string; deviceClientId: string; url: string; keys: { p256dh: string; auth: string; } | null; expires: string | null; types: string[] | null; } // For tracking last known states export interface AccountStates { [accountId: string]: { Email?: string; Mailbox?: string; Thread?: string; }; }