A campaign the backend cannot send says why and how to fix it
EmailService now pauses a campaign instead of failing its recipients one by one when it cannot send it: its From is off the platform relay's domain, or there is...
Warm-up says idle days don't count and draws the dates that slid
A warm-up day in which nothing is sent no longer counts: the run slides forward and the day repeats when sending resumes, which makes switching warm-up on befor...
Campaign mail the platform relay would refuse fails at once instead of being retried
The relay sends only as its own domain and answers anything else with a 451, so a campaign whose From is on another domain used to retry every recipient three t...
New host warm-up holds an org's campaign mail and releases it at the warm-up's pace
While an org's warm-up is on, the dispatcher leaves its campaigns alone and a releaser sends them one message at a time, the earliest due first across the org's...
Recipient rows carry contacted, and already-sent rows keep their mark beside the status
EmailService's recipient DTO now reports whether the campaign has already emailed each address. The mapper carries it through, together with lastError, and fill...
The campaign From field says when the bulk relay would refuse it
The campaign's own From field, defaulted from the bulk provider, warns when the address is off the provider's domain, as mail that may land in spam. On the plat...
Every campaign message names its recipient row in X-Kamo-Ref
The bulk relay logs the header against its queue id and strips it before delivery, so delivery results can be matched to the exact recipient row. The composer'...
The relay's delivery reports bounce, block and count campaign mail after hand-off
POST **************** takes the platform relay's reports of what became of each message, matched to the recipient row by the X-Kamo-Ref header or, failing that,...
The warm-up's schedule, pacing and health rules
A new sending IP is ramped over fourteen warm-up days. Days 1-7 follow a fixed schedule per pace (conservative, balanced, aggressive); from day 8 each day grows...
Warm-up pacing banner on /marketing/email
While the new host warm-up is pacing, campaigns go out far more slowly than their own settings say, and nothing on the campaign said why. The campaigns workspac...
Typed bulk sender client with field errors and the warm-up endpoints
The client knew a provider status called PENDING that the backend never sends, so a sender that was saved but not yet tested fell through to "Not configured". I...
Connection rule, presets and warm-up view model behind the bulk sender
The pure pieces the new screens are built on, each with tests: - the backend's port-first connection rule, mirrored so the form can say how KamoCRM will conn...
Rebuilt bulk sender tab with a new host warm-up panel
The Bulk Email Sender tab is rebuilt from one long form into a set of cards over a draft of the saved state: - a masthead with the live status (a saved but unt...
A campaign cannot be sent or scheduled without a bulk email sender
The dispatcher used to accept such a campaign and then skip it on every tick, leaving it at SENDING with nothing but a log line. sendNow and schedule now refuse...
The provider settings api answers with the saved state and names the field it refuses
PUT now returns the full settings state instead of {success: true}, which blanked the form after every save. Fields are validated server-side and refused as 400...
Preview the email as sent, a Custom / No Template audience, and a real From field
Preview: a dialog that renders the editor's own buildBodyHtml() output - the string Save stores and the dispatcher sends - so the audience's header, signature a...
Sign hello.kamocrm.com with its own customer key, by the From domain itself
Campaign mail leaves as hello.kamocrm.com through postfix-bulk. It gets its own DKIM key (selector customer, published as customer._domainkey.hello), and use_es...
Postfix-bulk, a second outbound relay for campaign mail, with delivery results fed back
Campaign mail now leaves through its own relay on k3m1 (egress 47.181.8.87) as hello.kamocrm.com, so complaints about bulk mail never touch the reputation of ma...
A campaign emails an address at most once, ever
Addresses are matched trimmed and case-insensitively, and a row the campaign has handed to the relay (sent, in flight, bounced, failed, or retried) is now its p...
NoReply Outbound, a god-only audit of mail sent as the platform NoReply address
A third section under Mail, shown only to god-eligible members, opens /messages/outbound/noreply: every message EmailService handed to the relay as the platform...
A ledger of every message sent as the platform NoReply address, readable by god only
Recorded in EmailSmtpService at the one place mail reaches the relay, and decided by the From address, so transactional templates, campaigns and article shares ...
A tracking link can land on the white-label CRM fees article
Adds **************** to the destinations the tracking-link picker offers on /marketing/tracking, with its own icon. The path is locale-free like its siblings: ...
Let a reader send the seat-fee article to someone they know
A "pass it on" form at the foot of **************** reached from a chip at the top and a line after the seven questions. The reader names up to three people and...
Email an article to someone, as the platform org, with a working opt-out
A visitor on the marketing site can send the seat-fee article to up to three people. POST /api/internal/article-share (X-Internal-Auth, like every other /api/in...
Put every page in /sitemap.xml itself, and list pages only in the languages they have
/sitemap.xml was an index, so opening it showed 79 file names rather than the site's pages. - /sitemap.xml is now one <urlset> with every page: 18,700 of them,...
A department's Select checks the members it is showing
The Directory's per-department Select used to switch the whole list into select mode with nothing checked, and read "Done" until pressed again. It now checks ev...
Public service announcement on who keeps software seat fees
New page at **************** explaining, for non-technical owners, how resold white-label platforms work: a flat agency license, per-seat fees the agency keeps,...
List every page in every language it exists in, and make each page agree
/sitemap.xml listed each page once, as its English URL. The 17,843 changelog entries had no language alternates at all, and every page's own hreflang named all ...
Say which locales each public article is really translated into
The marketing site's sitemap now lists every language version of every help-center, documentation and API-reference article, and each article page names the oth...
Say which locales each entry is really translated into
The marketing site's sitemap now lists every language version of every entry, and each entry page names the others as its hreflang alternates. A translation row...
Void an organization from Platform -> Configuration -> Organizations
The Organizations tab gains Active and Void sub-tabs, and each organization's drawer a way to void it — or, on the Void tab, to restore it. - Active / Void sub...
The roster no longer names a voided organization
An organization voided from Platform -> Configuration -> Organizations (orgs.is_active = FALSE) does not exist anywhere but the console's Void tab. findOwnedOrg...
Active and Void tabs in the platform org directory
The console's Organizations tab now splits into Active and Void sub-tabs. A voided organization is orgs.is_active = FALSE (set by SecurityService's void endpoin...
Void an organization, and let no way in reach a voided one
Platform -> Configuration -> Organizations can now void an organization. The void is orgs.is_active = FALSE; this commit adds the action and makes every way INT...
A voided organization is left out of every listing and host lookup
Platform operators can now void an organization from Platform -> Configuration -> Organizations. The void is orgs.is_active = FALSE — the flag sign-in and host ...
Topic titles in the bar's dropdowns sit on a darker plate of the brand
A menu's own name at its top and every section heading (Support's "Online Support", "Bugs & Enhancements", "Training"; Docs' "Create new") now sit on a rounded ...
Faces on messages only in conversations of three or more
A face beside every message tells people apart, and between two people the side a message is drawn on already does that - so the corner face now appears only wh...
The faces answer says how many people are in the conversation
GET **************** now carries `participants`: the console puts a face beside each message only when three or more people are in a conversation, since between...
Generate the sitemaps per request, and give every change its own page
/sitemap.xml was a metadata file prerendered at build time, in a container that cannot reach KBService or SecurityService, so every deploy shipped a sitemap wit...
Give every public entry an address, and page the list on the server
The public changelog served entries with no identifier, so the marketing site could neither link to one nor list them in a sitemap. Each entry now carries a slu...
Every message wears its author's face, on the bubble's corner
In every chat popup tool window - Chat, Support, Exec2Exec, Social, SMS, AI Chat - each message now carries a 16x16 photo that overlaps the bubble's top-left co...
The Signature Requests tab, and a colleague's save in the template editor
Signature Requests, between Templates and Common in the Docs manager: every document the collection's templates sent out for signature, in a grid paged on the s...
Signature requests for the Docs manager, with new counts per member
The Docs manager gets a Signature Requests tab: every document a collection's templates sent out for signature, in three buckets by signatures (nobody, some, or...
A save reaches every colleague with the template open
A save of a template's file told only the member who saved it, so a colleague with the same template open kept placing fields over pages the file had moved on f...
A face for every message in every chat window
GET **************** answers, for one conversation, the photo to draw beside each message: everybody on it now AND everybody who ever wrote in it (a roster forg...
A meeting link in the conversation, always on the platform's Kamo Meet
POST **************** lets either side of an Exec2Exec conversation add a meeting link, behind the same gate as sending a message. The meeting is created as the...
Add a meeting link to the conversation - always the platform's Kamo Meet
Both sides of an Exec2Exec window now carry the camera the other chat windows have: Add a meeting link. The meeting is created by MediaService as the PLATFORM o...
The desk's filters, faces and presence; an Exec2Exec badge that burns
Interaction Center > Chats > Exec2Exec gets two filters under the sub-tabs: Org Owner (All | Org-less | Org Owner) and Order By (Last Message | Latest Sign In) ...
Files and Templates, version history, and versioning settings
Members asked for documents that keep their history the way their organization chooses, and for templates that stand on their own instead of the Originals/Modif...
Faces on the desk — a client's photo, last sign-in and presence
The desk's roster now carries, for every client, their own photo (users.avatar_id, built on the operator's live theme host — the only one their console loads im...
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.
