Skip to content

v0.22.0

Choose a tag to compare

@heliocosta-dev heliocosta-dev released this 21 Oct 21:45
· 180 commits to main since this release
b467154

MillionSend v0.22.0 adds a date type for contact properties, next to string and number. A date property checks what gets written to it, segments can filter by dates, and the domain warm-up's Contact property list now shows only properties that hold dates. You can still keep dates in a string property, since segments and the warm-up read dates from any property. One database migration (0062). (#179)

In the dashboard

  • Audience → Properties: Date is a new type in the add dialog, the type filter and the table. A date property's fallback value must be a date.
  • Segments:
    • created_at and date properties offer is before, is after, is in the last N days and is more than N days ago.
    • Before and after take a date picker. The day operators take a whole number from 1 to 36,500.
    • Date properties keep every text operator, so is not set still finds contacts without one.
  • Domain → Warm-up → Contact property:
    • Lists date properties first, then other properties where at least half the values are dates.
    • Each option shows how many contacts hold a date in it and the newest one. With no dates anywhere, it points to Audience.
    • A count such as 3 no longer reads as a date in 1970, which made that contact look inactive. Contacts whose value isn't a date now count as unknown.

API and MCP

Additive only. Nothing changes for a team that doesn't define a date property.

  • POST /contact-properties takes "type": "date". Its fallback_value, on create and on PATCH, must be a date or gets 422 validation_error.
  • Contact create, update and batch refuse a value for a date property that isn't a date, with the same 422 validation_error a bad number gets.
  • GET /contacts/{id} and include=properties return { "type": "date", "value": "2026-01-08" } for a date property.
  • What counts as a date:
    • YYYY-MM-DD, read as midnight UTC.
    • A date and time with T or a space, optional seconds and an optional zone. It's read as UTC when it names no zone.
    • Unix time in seconds or milliseconds between the years 2000 and 2100.
  • Segment filters: property:<key> takes before, after, in_last_days and not_in_last_days, and created_at takes the two day operators. A value that isn't a date never matches.
  • MCP tools take the new type.

SDKs

  • .NET 0.10.0 and Rust 0.10.0 read the new type. Older versions of these two fail to list, read or create contact properties once a team has a date property, so upgrade them before adding one. Both now read a type they don't know as Unknown, so the next new type won't break them.
    • Rust 0.10.0 is a breaking release: ContactPropertyType gained Date and Unknown and is now #[non_exhaustive], so an exhaustive match needs a _ arm.
  • Node 0.11.0 adds date to its types.
  • Python, Go, Java, Ruby, PHP and Elixir read type as plain text, so any version works. Their docs now cover the date type.

Upgrading a self-hosted instance

  • Upgrade as usual. docker compose pull and docker compose up -d, or on Kubernetes --version 0.22.0.
  • One database migration, 0062, runs on start. It adds date to the contact_property_type enum. No table changes and no data rewritten.
  • No new environment variables or settings.
  • Rolling back to v0.21.1: Postgres can't remove an enum value, so date properties stay. v0.21.1 keeps their values as plain strings without checks, and refuses segment filters that use the new operators instead of matching more contacts.