Resolve recipients for event and send notification. Best-effort: logs
and swallows any failure so the caller's mutation is never affected.
Builds the email payload; only invoked when there is ≥1 recipient.
Id of the object this event concerns — equal to the notification's id.
Used for the creator backfill, and resolved before the payload is built
so we can skip building it when there are no recipients.
SendGrid template id for this notification, owned by the domain service.
Domain-agnostic notification core. Writer services hand it a
NotifiableEvent(the event they already publish) plus the EmailNotification payload their<Domain>NotificationServicebuilt; the core resolves who should be emailed and sends. This is the notification analogue ofTransactionCacheBuster— one injected collaborator the writer calls right after publish + cache-bust.notifyis best-effort: it never throws, so a SendGrid / PropelAuth / preferences failure can never fail the mutation that triggered it.Recipient resolution reproduces the customer-dashboard webhook handler exactly: customer-configured
emailAddresses, plus PropelAuth org users matching the configureduserIds/userGroupsor the object's dashboard "creator", each gated by the per-user preference overlay.