Skip to content

Releases: onetodone/mailer

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 11 Oct 20:56
f0ffa26

Patch Changes

  • 7e5a398: Run the main entry and the Resend transport on Bun, Deno and edge runtimes such as Cloudflare Workers.

    • The main entry and @onetodone/mailer/resend import no Node.js built-in modules, so they load without Node.js compatibility flags. @onetodone/mailer/smtp still needs Node.js.
    • A failing onSent or onError hook is reported with process.emitWarning as a MailerWarning where process.emitWarning exists, and with console.warn elsewhere.

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 11 Oct 20:27
fdf7577

Minor Changes

  • 5b43735: Give layouts the text direction of the email as LayoutContext.dir.

    • dir is 'rtl' for languages written right to left, such as Arabic and Hebrew, and 'ltr' otherwise. Set it as the dir attribute of your layout's markup.
    • dir is required, so code that builds a LayoutContext by hand, such as a unit test of a custom layout, needs it too. Layouts passed to createMailer need no change.
    • Migration: add dir where you build a LayoutContext yourself, for example defaultLayout({ ...context, dir: 'ltr' }) or { branding, theme, locale: 'en', dir: 'ltr', subject, preheader, content, messages }.
  • f9a5407: Remove the UiMessages type from the public exports.

    • No exported function or type uses it, so it described nothing users can pass or receive.
    • Migration: if you import UiMessages, replace it with { readonly linkFallback: string }.
  • f9a5407: Rename the ctaUrl prop of the welcome template to startUrl.

    • WelcomeProps has startUrl instead of ctaUrl: an absolute http: or https: link behind the "Get started" button, branding.appUrl by default. The name follows the other link props, which are named after their action (verifyUrl, resetUrl, signInUrl).
    • send and render reject ctaUrl with INVALID_PROPS.
    • Migration: replace props: { ctaUrl } with props: { startUrl } in mailer.send('welcome', …) and mailer.render('welcome', …).

Patch Changes

  • f9a5407: Remove the unused zod import from the type declarations.

    • Type checking a project that uses the package does not load zod's declarations through it. zod stays a runtime dependency.
    • No exported type changes.
  • f9a5407: Document the semver policy of the MailerErrorCode type: codes can be added in a minor release.

    • A switch over error.code needs a default branch. Existing codes keep their meaning.
  • f9a5407: Make instanceof MailerError work across the ESM and CommonJS builds.

    • When an app loads both builds, for example an ESM app with a CommonJS dependency that also uses the package, error instanceof MailerError holds for errors from either build.
    • instanceof against your own subclass of MailerError matches only instances of that subclass.
  • 33827e1: Add a Resend transport: resendTransport from @onetodone/mailer/resend.

    • resendTransport({ apiKey, baseUrl?, fetch? }) sends through the Resend API with the built-in fetch and needs no extra package.
    • Every field of the email is sent, including cc, bcc, reply-to, headers and attachments. Attachments with a cid go out as inline images.
    • send resolves with the Resend email ID as messageId.
    • A failed delivery rejects with TRANSPORT_FAILED, with the HTTP status in status and Resend's error response in cause. retryable is true for a rate limit or quota, a conflict, a server error or a network failure, and false for any other 4xx.
    • Invalid settings throw INVALID_CONFIG; the API key never appears in the message.
  • 33827e1: Tell retryable delivery failures from rejected emails through MailerError.retryable and MailerError.status.

    • retryable is true when the same email may be delivered on a later attempt, false when another attempt fails the same way, and undefined when unknown.
    • status holds the SMTP reply code or the HTTP status of the provider's API when the provider answered.
    • smtpTransport sets them on TRANSPORT_FAILED: a 4xx reply, a lost connection or a timeout is retryable, a 5xx reply is not.
    • Your own transport can set them by throwing new MailerError('TRANSPORT_FAILED', message, { cause, retryable, status }); the MailerErrorOptions type describes the options.
    • The meaning of TRANSPORT_FAILED is unchanged, and errors your transport throws without these fields keep them undefined.
  • 5b43735: Render emails in right-to-left languages, such as Arabic and Hebrew, right to left.

    • The direction follows the email's locale. For a right-to-left locale the built-in layout sets dir="rtl" and aligns the content to the right, and Outlook on Windows aligns buttons, codes and images to the right too.
    • Codes from ui.code and the link from ui.linkFallback stay left to right inside right-to-left text, so 123 456 keeps its order.
    • Templates receive the direction as dir ('ltr' or 'rtl') next to locale, for markup of their own.
    • Emails in left-to-right languages render exactly as before.

v0.2.6

Choose a tag to compare

@github-actions github-actions released this 11 Oct 18:09
b170b4e

Patch Changes

  • 5d9000a: Add built-in texts in Chinese (Simplified).

    • Locale gains zh. The locale setting and the locale option of send and render accept it without messages.
    • If you already send in Chinese (Simplified) through messages, your overrides still win, and the keys you leave out come from the built-in texts instead of English.
    • Thanks @SuparvaCode for the translation!

v0.2.5

Choose a tag to compare

@github-actions github-actions released this 11 Oct 16:56
94158d6

Patch Changes

  • 05143f7: Document integrations and show every email in the README and docs.

    • Screenshots of every built-in email, and a live preview of every email in every built-in language.
    • Recipes for Better Auth, Auth.js, Express, Fastify, Next.js, NestJS and BullMQ.
    • No changes to the API or to the rendered emails.

v0.2.4

Choose a tag to compare

@github-actions github-actions released this 05 Oct 02:45
8f68eca

Patch Changes

  • b762136: Add plural forms to the texts of custom templates.

    • A text in a template's messages may be plural forms instead of a string: one text per Intl.PluralRules category (zero, one, two, few, many, other), such as items: { one: '{count} item', other: '{count} items' }. other is required in en.
    • t('<name>.<key>', { count }) and t.html pick the form for count through the plural rules of the email's locale; {count} is the number formatted for the locale. A category without a form uses other. count is required at compile time for texts with plural forms.
    • Other locales of the template and the mailer's messages give plural forms for those keys category by category and may add categories the English texts leave out, such as few and many. Categories a locale leaves out fall back to English.
    • createMailer throws INVALID_CONFIG for plural forms without other in en, an unknown plural category, and a locale text whose form differs from en (a string where en has plural forms, or the other way round).
    • TemplateTexts and TemplateMessages accept plural forms. Translate and TemplateRenderContext take an optional second type parameter with the keys of texts with plural forms.

v0.2.3

Choose a tag to compare

@github-actions github-actions released this 03 Oct 19:37
2a84dd7

Patch Changes

  • f993009: Add built-in text in Belarusian (Latin).

    • Locale gains be-Latn. The locale setting and the locale option of send and render accept it without messages.
    • If you already send in Belarusian (Latin) through messages, your overrides still win, and the keys you leave out come from the built-in text instead of English.

v0.2.2

Choose a tag to compare

@github-actions github-actions released this 30 Sep 00:06
510da01

Patch Changes

  • 51208d0: Add built-in texts in Czech, Estonian, French, Georgian, German, Italian, Japanese, Latvian, Lithuanian, Polish, Romanian, Thai and Ukrainian.

    • Locale gains cs, de, et, fr, it, ja, ka, lt, lv, pl, ro, th and uk. The locale setting and the locale option of send and render accept them without messages.
    • The texts address the reader politely (Sie, vous, vy, ви and so on), except Polish and Italian, which use the informal form common in apps there. Reword any text through messages.
    • If you already send in one of these languages through messages, your overrides still win, and the keys you leave out come from the built-in texts instead of English.

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 29 Sep 12:42
03a5959

Patch Changes

  • 817dab4: Document the semver policy of the Locale type: built-in locales can be added in any release.

    • Locale lists the built-in locales and gains values whenever a built-in locale is added, in any release, so code that requires every Locale value (such as Record<Locale, …>) is not covered by semver.
    • If you already use a locale through messages and it becomes built-in, your overrides still win; keys you did not override come from the built-in texts instead of English.
  • 1f1d989: Add per-locale texts to custom templates.

    • defineTemplate accepts messages: the template's texts by locale. en is required and lists every text key; other locales may leave keys out, which fall back to English key by key. Plural forms are not supported in template texts.
    • In a template with messages, t and t.html take the template's own keys under its name, such as t('invoice.subject', { number }), plus the common keys, and reject any other key at compile time. A template without messages keeps t for every built-in key.
    • The messages setting of createMailer overrides the texts of registered custom templates under their names, with the same English fallback as the built-in texts. MessagesOverrides<typeof templates> and LocaleMessages<typeof templates> type such overrides outside the createMailer call.
    • A custom template with messages that replaces a built-in template also replaces the built-in texts of that template in every locale.
    • createMailer throws INVALID_CONFIG for template texts that are not strings, a missing en, a key that en does not have, a locale that is neither built-in nor a key of messages, and a template with messages named common or containing a dot.
    • Types TemplateMessages and TemplateTexts. Template, TemplateRenderContext, Translate, MessagesOverrides and LocaleMessages take optional type parameters, and TemplateProps accepts templates with messages.

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 03:58
f84bb79

Minor Changes

  • 7bc8714: Add built-in emails that confirm an account deletion and tell the owner once the account is deleted.

    • confirmAccountDeletion asks the owner to confirm the deletion with a button to confirmUrl, and warns that a deleted account and its data can't be restored. Props: confirmUrl, userName, expiresInMinutes (ConfirmAccountDeletionProps).
    • accountDeleted tells the owner that the account was deleted, with a way to contact support if it wasn't them (supportUrl, else branding.supportEmail). Every prop is optional: userName, supportUrl (AccountDeletedProps).
    • Texts in English and Belarusian, overridable through messages in the confirmAccountDeletion and accountDeleted sections. Apps that keep deleted accounts for a grace period can reword confirmAccountDeletion.warning and accountDeleted.farewell.
  • 45611f1: Add built-in templates for changing the email address.

    • verifyEmailChange goes to the new address and asks the user to confirm it. Props: verifyUrl, userName, expiresInMinutes (VerifyEmailChangeProps).
    • emailChangeRequested goes to the current address when a change is requested. It names newEmail and offers a button that cancels the change (cancelUrl), or a way to contact support without it (supportUrl, else branding.supportEmail). Props: newEmail, userName, requestedAt, timeZone, ip, cancelUrl, supportUrl (EmailChangeRequestedProps).
    • emailChanged goes to the old address once the change is done, with a way to contact support. Every prop is optional: userName, newEmail, changedAt, timeZone, ip, supportUrl (EmailChangedProps).
    • newEmail accepts any non-empty text, so a masked address such as l***@example.com works.
    • Texts in English and Belarusian, overridable through messages in the verifyEmailChange, emailChangeRequested and emailChanged sections.
    • Messages describes the full built-in dictionary and gains keys whenever built-in templates are added, in any release, so a full dictionary typed as Messages is not covered by semver. Use MessagesOverrides (or LocaleMessages for one locale) for your own texts; keys you leave out fall back to English.
    • Polish the Belarusian wording of the resetPassword intro: «Націсніце кнопку, каб задаць новы пароль.»
    • Migration: if you type a full dictionary as Messages, add the verifyEmailChange, emailChangeRequested and emailChanged sections, or check it with satisfies MessagesOverrides instead, so that missing keys fall back to English.
  • ffa8d14: Add built-in security notices for new sign-ins, two-factor authentication changes and locked accounts.

    • newSignIn tells the owner about a sign-in, such as from a new device, and lists signedInAt, device, location and ip when you pass them. It offers a button to a page that secures the account (secureUrl), or a way to contact support without it (supportUrl, else branding.supportEmail). Every prop is optional: userName, signedInAt, timeZone, ip, device, location, secureUrl, supportUrl (NewSignInProps).
    • twoFactorEnabled and twoFactorDisabled tell the owner that two-factor authentication was turned on or off, with a way to contact support. Every prop is optional: userName, changedAt, timeZone, ip, supportUrl (TwoFactorEnabledProps, TwoFactorDisabledProps).
    • accountLocked tells the owner that the account was locked after too many failed sign-in attempts, shows lockedUntil and ip when you pass them, and offers a button that unlocks the account (unlockUrl), or help from support without it (supportUrl, else branding.supportEmail). It ends with advice to choose a new password for owners who did not try to sign in. Every prop is optional: userName, lockedUntil, timeZone, ip, unlockUrl, supportUrl (AccountLockedProps).
    • Texts in English and Belarusian, overridable through messages in the newSignIn, twoFactorEnabled, twoFactorDisabled and accountLocked sections.
  • a32a33f: Add built-in templates for one-time codes, sign-in links and welcome emails.

    • otpCode sends a one-time code for sign-in, two-step verification or confirming an action. Props: code, userName, expiresInMinutes (OtpCodeProps). The subject and inbox preview leave out the code, because they show in notifications and on lock screens; both texts accept {code}, so a messages override can add it.
    • magicLink sends a link that signs the user in without a password and tells the reader not to share it. Props: signInUrl, userName, expiresInMinutes (MagicLinkProps).
    • welcome greets a new user with a button to ctaUrl, or to branding.appUrl without it. Every prop is optional: userName, ctaUrl (WelcomeProps).
    • Texts in English and Belarusian, overridable through messages in the otpCode, magicLink and welcome sections.

Patch Changes

  • 99f9462: Add attachments and inline images.

    • mailer.send accepts attachments: files with a filename, content (a Buffer, a Uint8Array, or text sent as UTF-8), an optional contentType and an optional cid. Without contentType, the type is guessed from the file name extension, with application/octet-stream as the fallback, and text content gets ; charset=utf-8.
    • An attachment with a cid is an inline image that the HTML shows through cid:<cid>. After rendering, send checks the HTML, layout included, and rejects with INVALID_OPTIONS naming every cid: reference without an attachment, before anything is sent. An attachment whose cid the HTML never references is sent as a regular attachment.
    • ui.image(src, { alt, width, height }) shows an image from an absolute http: or https: URL, or an attachment through a cid: reference. It renders email-safe markup with an explicit width (534 px, the content width, by default and at most), shrinks on narrow screens, and shows the alt text in the plain-text version. An invalid source throws UNSAFE_URL.
    • File names and content types with line breaks or other control characters are rejected with INVALID_OPTIONS, so attachments cannot inject MIME headers through any transport. Content types must be MIME types, and a cid uses ASCII letters, digits, ., _, - and @ and is unique within an email.
    • smtpTransport delivers attachments, with inline images next to the HTML. consoleTransport prints the name, type and size of each attachment, and memoryTransport records them in sent.
    • OutgoingMessage has an optional attachments list, in which contentType is always set and cid is set only on referenced inline images. A custom transport must deliver every attachment or reject.
    • Hook events list the filename, contentType and size of each attachment, never its content.
    • Types Attachment, OutgoingAttachment, AttachmentInfo and ImageOptions.

v0.1.1

Choose a tag to compare

@github-actions github-actions released this 28 Sep 23:36
bdec2e9

Patch Changes

  • d50257b: Remove source maps from the published package, which halves its unpacked size. The JavaScript and type declarations are unchanged apart from their sourceMappingURL comments. The JavaScript is not minified, so stack traces that point into dist stay readable.