Refuse a mailbox past the organization's email licenses
Owner rule 2026-10-22: per-user add-ons bill the licenses purchased; how many mailboxes may be in use is limited only by them. Before a mailbox is put into use,...
BILLING_INVOICE, gated on viewing subscription invoices
Raised by SecurityService to the selling organization's owners when a subscription invoice draft is waiting for review or a customer's invoice goes past due. Al...
Fixtures stamp the god-mode window's end; an elapsed window is not elevated (shared SessionPlatformFacts expiry)
**************** now also needs godModeExpiresAt ahead (kamo-shared-library 1.6.1). **************** god fixture carries the stamp, and a new case pins that an ...
Email templates and the org calendar/contacts connection take MANAGE_EMAIL_SETTINGS (SITP TP02)
EmailTemplateController and EmailTemplateCategoryController checked a session alone: any member could list, read, preview, create, edit, archive, duplicate or r...
An RSVP from a member with no mailbox says so (409 NO_MAILBOX), not a bare 400 (SITP TP12 live smoke)
An event names its organiser; an RSVP that cannot be taken says why (SITP TP12)
- EventDto carries organizerEmail, so the Tool Plane's calendar_rsvp names who the answer is mailed to (and classifies an outside organiser as an external mee...
A shared-mailbox send meets the SI guards; message labels take ?folder= (SITP TP13)
A send as a shared mailbox skipped the checks EmailController#sendEmail runs: an own-domain recipient that is nobody (422 RECIPIENTS_UNKNOWN), the SI thread-tur...
Stop logging the database password at startup
com.zaxxer.hikari at DEBUG makes HikariConfig print its whole configuration on every start, including dataSourceProperties {password=...} and password......; Pr...
IOT_ALARM phone push body and withdraw-with-update (SP10)
An IOT_ALARM event card (source **************** as iot-service's AlarmNotifier writes it, or <alarmUuid>:<seq>) is mirrored as an IOT_ALARM push: channel/colou...
Preview sample variables for the iot share letters
Rebuilt on the new shared library BEFORE IoTService sends (a missing template key 404s forever).
NoReplySubsystem.IOT, the preview sample and mirrorToPush
IoT Devices SP06: alarm letters (iot.alarm_notice) audit under IOT; the template preview has sample values; POST /api/internal/notifications takes an optional m...
An unsubscribe from one of the organization's own protected addresses is noted, not listed
Owner 2026-10-15: the do-not-block list beside the do-not-contact list. DoNotContactEmailBeans declares shared-lib's DoNotBlockList and hands it to the DoNotCon...
Gate the RPM_ALERT kind on REVIEW_CLINICAL_RESULTS and list it after LEAD_CALLBACK
Email unsubscribes reach the do-not-contact list, and campaigns, shares and an SI's mail check it
Owner 2026-10-15: one company-wide do-not-contact list per organization, scoped per channel; an email unsubscribe blocks email only. - Writer: MirroringEmailOp...
A meeting that arrives by email asks once, then keeps itself current
A new invitation in the mail reader now offers "Add to calendar". Once a member has added it, the organiser's follow-ups apply on their own: a moved time, a new...
A member's mail carries the name on their member profile
9351aac named a nameless From with the mailbox row's display_name first, and kept any name the request sent. The composer sends that same row name, and rows can...
A member's mail goes out under their name, not a bare address
The From header carried a name only when the request did, and the composer sends the mailbox's display_name: set for an SI's mailbox when it is made, blank on a...
An alias-domain From row names the mailbox behind it
The From picker offers the member's primary mailbox again on each org alias domain, with an id like <mailbox>:alias-domain:<domain> to keep it unique in the lis...
Gate the eight IoT kinds on their rights with the owner rule, in one display order (IoT SP00)
Rebuild onto kamo-shared-library 6fce139a
Seeds the new SUSPICIOUS_SIGNIN_DETECTED canonical template, which SecurityService sends for a detection rule's NOTIFY_ADMIN_EMAIL response.
Preview the new-lead-available letter
Adds the LEADS_AVAILABLE arm to sampleVariables, built through the same shared-lib LeadsAvailableEmail helper SecurityService sends with, so the admin preview s...
An SI's HIGH chat card is raised even while an unread-chat card stands
A person with an undismissed CHAT_MESSAGE card was never told of an SI's NOTIFY (KamoCollab CP12 D14): the announce-once rule dropped the HIGH card too, while t...
A meeting's updates and cancellations come from the address that invited its guests
The composer files a meeting under whatever its From said, an alias or a shared mailbox, and that address is the ORGANIZER in every ics. But updates, cancellati...
File a message's search-index row and lead link under its thread id, not the conversation row's surrogate
conversations.thread_id is generated (@GeneratedValue on ConversationEntity, primary key the thread id alone), so the row **************** returns carries a ran...
CALENDAR_EVENT labels and thread keys on mail rows β the labels endpoint serves every resolver, CalendarEventLabelResolver labels an event of the org (owner, member, department and job-title audiences through the org graph, member attendees; others EMAIL:), and search and conversation rows carry threadKey (KamoCollab CP07 Task 7)
CalendarEventLabelReads reads the event by primary key and organization (live only), its audience and attendees by the event-id indexes, and users to members by...
Confidential thread markers and EMAIL_THREAD labels β PUT β¦/thread-confidential on member and shared mailboxes, one audited writer, threadKey and threadConfidential on both message GETs, POST **************** the org graph (KamoCollab CP05 Task 20)
EmailThreadKeys is the one thread-naming rule **************** now calls it): root Message-ID, UUIDv5 thread id, and the EMAIL_THREAD key without angle brackets...
Declare the disclosure ledger recorder, paired with its repository scan (KamoCollab CP08 Task 12)
DisclosureLedgerConfig declares DisclosureRecorder; EmailServiceApplication's @EnableJpaRepositories gains **************** in the same commit. DisclosureLedger...
The two contact notification kinds, and which members an internal address reaches (KamoCollab CP04 Task 11)
CONTACT_REQUESTED and CONTACT_DECIDED are gated on ACCESS_CHAT and listed after MENTIONED. POST **************** ({orgId, addresses[]}, at most 100, KAMOAI_INTE...
The CP05 DDL for per-thread Confidential markers and the thread_id indexes
KamoCollab CP05 Task 4 (spec 5.1): public.email_thread_labels keyed by (org_id, thread_key), ix_thread_messages_thread and the partial ix_search_index_thread. H...
Labels page in one date order with an exact total; Microsoft 365 folders are counted
Labels - A label was paged through the join table by UID and each page sorted by date afterwards. UIDs only order mail within one folder and a label spans f...
Message listings say how many messages they hold (X-Total-Count)
The message list in kamo-internal can now be browsed by pages, and its pager needs the listing's size for "51-100 of 1,240" and a Last button. Every listing ans...
Lower-case NATS mailbox subjects for live updates
Mixed-case addresses like Sales@kamocrm.com published on different NATS subjects than subscribers used, so watched mailboxes never refreshed.
A composed message carries its meeting, and calendar edits ask before telling guests
- /api/email/send takes meetingInvite: the event is filed on the sender's calendar in the same transaction, its ics rides on the composed message with an X-...
An AI hire no longer waits forever on an email provider that was never connected
An org that chose Google Workspace (or another third-party provider) but left it at PENDING_SETUP, or switched it off, can never produce the AI's mailbox, so th...
A provisioning race Yugabyte reports as a serialization conflict no longer 500s the calendar widget (SP98 T26)
listCalendars provisions the shared and the personal calendar find-then-create, each in its own transaction, and treated a lost race as done only when it surfac...
MailSearchWiringTest registers the recipient-domain validator EmailController now takes (SP98 T26)
ec2c638 gave EmailController a RecipientDomainValidator; the wiring test's context did not have one, so it has failed on main since 2026-09-28 **************** ...
Calendar chat lines say they are system lines (KamoCollab CP00 T5)
MediaChatClient.sendDirect now posts "source": "SYSTEM" beside fromMemberId, toMemberId and message: a calendar invitation or cancellation is a notice written i...
A member's new name reaches their mailbox's display name (SP95 T35)
POST **************** {previous, current} -> {updated}, behind the KamoAI internal secret like provision-mailbox. The mailboxes the member holds as primary whos...
The AI signature disclosure names the company by its spoken name
An AI member's email disclosure filled {organization} with the organization's title (its letterhead), so Luna's mail said "an AI member of the KamoCRM Inc. team...
Key the cross-root retry on alias-domain membership, not root-or-not
Round 3 review (email-fix-review-3.md) confirmed round 2's BLOCKER fixed (walked sage@kamouniverse.com through both the app code and Postfix's own platform-alia...
Retry every owned domain unconditionally, and drop the +tag fold
Round 2 review (email-fix-review-2.md) found the round 1 fix for MAJOR #3 (multiple root domains) still reopened the original bug: - BLOCKER: kamouniverse.com ...
Close three false-refusal paths the review found in RecipientDomainValidator
Independent review of D-luna-1 (email-fix-review-1.md) found two BLOCKERs and a MAJOR, each a real false refusal of legitimate mail, demonstrated from code alre...
Refuse a guessed recipient at the org's own domain before it reaches the mail server
Luna (AI member) asked to email the owner and guessed **************** instead of looking up the real address (sage@kamocrm.com). kamouniverse.com is one of the...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
