ObjectStackObjectStack

Email Config

Email Config protocol schemas

Email Service Configuration Protocol

Operator-facing configuration that selects the outbound email transport for the EmailServicePlugin. Provider is a provider tag

  • provider-specific settings; concrete IEmailTransport implementations live in @objectstack/plugin-email/transports/*.

Resolution order in serve.ts:

  1. config.email.* from objectstack.config.ts
  2. OS_EMAIL_* environment variables (override per setting)
  3. Default → provider='log' (LogTransport, no real send)

appName is the one key whose env layer is not OS_EMAIL_* — it is OS_APP_NAME, because the same product name names the whole deployment, not just its mail.

Every key here is one resolveEmailCapabilityArg reads (the single reader of config.email); the schema is the operator-facing contract for that function, so a key the runtime honours and this object omits is a type error on a config that boots fine — the declared ≠ implemented gap of #5104 (provider='smtp') and #5307 (queueDelivery / appName / defaultTemplateContext), both times with the spec on the lagging side.

SMTP delivery is built in (ADR-0012): select it with provider='smtp' and supply the connection through options (host / port / secure / user / password) or the matching OS_EMAIL_SMTP_HOST / _PORT / _SECURE / _USER / _PASSWORD environment variables.

Source: packages/spec/src/system/email-config.zod.ts

TypeScript Usage

import { EmailAddressConfigSchema, EmailProviderSchema, EmailServiceConfigSchema } from '@objectstack/spec/system';
import type { EmailAddressConfig, EmailProvider, EmailServiceConfig } from '@objectstack/spec/system';

// Validate data
const result = EmailAddressConfigSchema.parse(data);

EmailAddressConfig

Properties

PropertyTypeRequiredDescription
namestringoptionalDisplay name (e.g. "Acme CRM")
addressstringRFC-5322 address

EmailProvider

Allowed Values

  • log
  • resend
  • postmark
  • smtp

EmailServiceConfig

Properties

PropertyTypeRequiredDescription
providerEnum<'log' | 'resend' | 'postmark' | 'smtp'>Transport to deliver through (OS_EMAIL_PROVIDER env). Default log — boots, sends nothing
apiKeystringoptionalProvider API key (or OS_EMAIL_API_KEY env)
defaultFrom{ name?: string; address: string }optional
retriesintegeroptionalRetry attempts on transport throw
persistbooleanoptionalPersist to sys_email (default true)
queueDeliverybooleanoptionalDeliver through the durable sys_job_queue instead of inline (or OS_EMAIL_QUEUE_ENABLED env). Default false. Reuses retries as the queue attempt budget; requires a queue service and sys_email persistence, else the boot fails
optionsRecord<string, any>optionalProvider-specific extras. smtp: host (required) / port / secure / user / password, mirroring OS_EMAIL_SMTP_HOST / _PORT / _SECURE / _USER / _PASSWORD. postmark: messageStream
appNamestringoptionalProduct name templates interpolate as the appName variable — OS_APP_NAME env wins, then this, then defaultTemplateContext.appName, then the top-level config appName, then "ObjectStack". Also seeds the placeholder no-reply sender when no defaultFrom is configured
defaultTemplateContextRecord<string, any>optionalFree-form render context merged into every sendTemplate() call, under the per-call data. Passed through unchanged except appName, which is resolved by its own chain — OS_APP_NAME and the appName key both override the value written here

On this page