├── .changeset ├── README.md ├── config.json ├── curly-fireants-allow.md ├── dry-humans-return.md ├── fast-countries-marry.md ├── many-donuts-retire.md ├── new-coats-cover.md ├── odd-bobcats-know.md ├── old-suits-promise.md ├── pre.json ├── tame-windows-look.md └── wild-mugs-kick.md ├── .github ├── DISCUSSION_TEMPLATE │ ├── help.yml │ └── ideas.yml ├── ISSUE_TEMPLATE │ ├── 1.bug_report.yml │ └── config.yml ├── pull_request_template.md └── workflows │ ├── bump-canary.yml │ ├── bump-stable.yml │ └── tests.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── apps ├── demo │ ├── .gitignore │ ├── emails │ │ ├── magic-links │ │ │ ├── aws-verify-email.tsx │ │ │ ├── linear-login-code.tsx │ │ │ ├── notion-magic-link.tsx │ │ │ ├── plaid-verify-identity.tsx │ │ │ ├── raycast-magic-link.tsx │ │ │ └── slack-confirm.tsx │ │ ├── newsletters │ │ │ ├── codepen-challengers.tsx │ │ │ ├── google-play-policy-update.tsx │ │ │ └── stack-overflow-tips.tsx │ │ ├── notifications │ │ │ ├── github-access-token.tsx │ │ │ ├── vercel-invite-user.tsx │ │ │ └── yelp-recent-login.tsx │ │ ├── receipts │ │ │ ├── apple-receipt.tsx │ │ │ └── nike-receipt.tsx │ │ ├── reset-password │ │ │ ├── dropbox-reset-password.tsx │ │ │ └── twitch-reset-password.tsx │ │ ├── reviews │ │ │ ├── airbnb-review.tsx │ │ │ └── amazon-review.tsx │ │ ├── static │ │ │ ├── airbnb-logo.png │ │ │ ├── airbnb-review-user.jpg │ │ │ ├── amazon-book.jpg │ │ │ ├── amazon-facebook.jpg │ │ │ ├── amazon-instagram.jpg │ │ │ ├── amazon-logo.png │ │ │ ├── amazon-prime-logo.png │ │ │ ├── amazon-rating.gif │ │ │ ├── amazon-twitter.jpg │ │ │ ├── apple-card-icon.png │ │ │ ├── apple-hbo-max-icon.jpeg │ │ │ ├── apple-logo.png │ │ │ ├── apple-wallet.png │ │ │ ├── aws-logo.png │ │ │ ├── codepen-challengers.png │ │ │ ├── codepen-cube.png │ │ │ ├── codepen-pro.png │ │ │ ├── dropbox-logo.png │ │ │ ├── github.png │ │ │ ├── google-play-academy.png │ │ │ ├── google-play-chat.png │ │ │ ├── google-play-footer.png │ │ │ ├── google-play-header.png │ │ │ ├── google-play-icon.png │ │ │ ├── google-play-logo.png │ │ │ ├── google-play-pl.png │ │ │ ├── google-play.png │ │ │ ├── koala-logo.png │ │ │ ├── linear-logo.png │ │ │ ├── netlify-logo.png │ │ │ ├── nike-logo.png │ │ │ ├── nike-phone.png │ │ │ ├── nike-product.png │ │ │ ├── nike-recomendation-1.png │ │ │ ├── nike-recomendation-2.png │ │ │ ├── nike-recomendation-3.png │ │ │ ├── nike-recomendation-4.png │ │ │ ├── notion-logo.png │ │ │ ├── plaid-logo.png │ │ │ ├── raycast-bg.png │ │ │ ├── raycast-logo.png │ │ │ ├── slack-facebook.png │ │ │ ├── slack-linkedin.png │ │ │ ├── slack-logo.png │ │ │ ├── slack-twitter.png │ │ │ ├── stack-overflow-header.png │ │ │ ├── stack-overflow-logo-sm.png │ │ │ ├── stack-overflow-logo.png │ │ │ ├── stripe-logo.png │ │ │ ├── twitch-icon-facebook.png │ │ │ ├── twitch-icon-twitter.png │ │ │ ├── twitch-logo.png │ │ │ ├── vercel-arrow.png │ │ │ ├── vercel-logo.png │ │ │ ├── vercel-team.png │ │ │ ├── vercel-user.png │ │ │ ├── yelp-footer.png │ │ │ ├── yelp-header.png │ │ │ └── yelp-logo.png │ │ └── welcome │ │ │ ├── koala-welcome.tsx │ │ │ ├── netlify-welcome.tsx │ │ │ └── stripe-welcome.tsx │ ├── license.md │ └── package.json ├── docs │ ├── changelog.mdx │ ├── cli.mdx │ ├── components │ │ ├── button.mdx │ │ ├── code-block.mdx │ │ ├── code-inline.mdx │ │ ├── column.mdx │ │ ├── container.mdx │ │ ├── font.mdx │ │ ├── head.mdx │ │ ├── heading.mdx │ │ ├── hr.mdx │ │ ├── html.mdx │ │ ├── image.mdx │ │ ├── link.mdx │ │ ├── markdown.mdx │ │ ├── preview.mdx │ │ ├── row.mdx │ │ ├── section.mdx │ │ ├── tailwind.mdx │ │ └── text.mdx │ ├── contributing.mdx │ ├── favicon.png │ ├── getting-started │ │ ├── automatic-setup.mdx │ │ ├── manual-setup.mdx │ │ ├── migrating-to-react-email.mdx │ │ └── monorepo-setup │ │ │ ├── bun.mdx │ │ │ ├── choose-package-manager.mdx │ │ │ ├── npm.mdx │ │ │ ├── pnpm.mdx │ │ │ └── yarn.mdx │ ├── images │ │ ├── background.png │ │ ├── bg.png │ │ └── local-dev.jpg │ ├── integrations │ │ ├── aws-ses.mdx │ │ ├── mailersend.mdx │ │ ├── nodemailer.mdx │ │ ├── overview.mdx │ │ ├── plunk.mdx │ │ ├── postmark.mdx │ │ ├── resend.mdx │ │ ├── scaleway.mdx │ │ └── sendgrid.mdx │ ├── introduction.mdx │ ├── license.md │ ├── logo │ │ ├── dark.svg │ │ └── light.svg │ ├── mint.json │ ├── package.json │ ├── roadmap.mdx │ ├── snippets │ │ ├── localdev.mdx │ │ ├── next-steps.mdx │ │ └── support.mdx │ └── utilities │ │ └── render.mdx └── web │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── license.md │ ├── next-env.d.ts │ ├── next.config.js │ ├── package.json │ ├── postcss.config.js │ ├── public │ └── static │ │ ├── apple-touch-icon.png │ │ ├── bg.png │ │ ├── cover.png │ │ ├── covers │ │ ├── button.png │ │ ├── code-block.png │ │ ├── code-inline.png │ │ ├── column.png │ │ ├── components.png │ │ ├── container.png │ │ ├── create-email.png │ │ ├── font.png │ │ ├── head.png │ │ ├── heading.png │ │ ├── hr.png │ │ ├── html.png │ │ ├── img.png │ │ ├── link.png │ │ ├── markdown.png │ │ ├── preview.png │ │ ├── react-email.png │ │ ├── render.png │ │ ├── row.png │ │ ├── section.png │ │ ├── tailwind.png │ │ └── text.png │ │ ├── examples │ │ ├── airbnb-review.png │ │ ├── apple-receipt.png │ │ ├── aws-verify-email.png │ │ ├── dropbox-reset-password.png │ │ ├── github-access-token.png │ │ ├── google-play-policy-update.png │ │ ├── koala-welcome.png │ │ ├── linear-login-code.png │ │ ├── nike-receipt.png │ │ ├── notion-magic-link.png │ │ ├── plaid-verify-identity.png │ │ ├── raycast-magic-link.png │ │ ├── slack-confirm.png │ │ ├── stack-overflow-tips.png │ │ ├── stripe-welcome.png │ │ ├── twitch-reset-password.png │ │ ├── vercel-invite-user.png │ │ └── yelp-recent-login.png │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── icons │ │ ├── apple-mail.svg │ │ ├── gmail.svg │ │ ├── hey.svg │ │ ├── outlook.svg │ │ ├── superhuman.svg │ │ └── yahoo-mail.svg │ │ ├── logo.png │ │ └── resend.png │ ├── src │ ├── app │ │ ├── api │ │ │ └── send │ │ │ │ └── test │ │ │ │ └── route.ts │ │ ├── examples │ │ │ └── page.tsx │ │ ├── globals.css │ │ ├── inter.ts │ │ ├── layout.tsx │ │ └── page.tsx │ ├── components │ │ ├── anchor.tsx │ │ ├── button.tsx │ │ ├── code.tsx │ │ ├── example.tsx │ │ ├── footer.tsx │ │ ├── heading.tsx │ │ ├── icon-button.tsx │ │ ├── icons │ │ │ ├── icon-arrow-right.tsx │ │ │ ├── icon-base.tsx │ │ │ ├── icon-check.tsx │ │ │ ├── icon-clipboard.tsx │ │ │ └── index.ts │ │ ├── logo.tsx │ │ ├── menu.tsx │ │ ├── text.tsx │ │ └── topbar.tsx │ └── utils │ │ ├── as.ts │ │ └── unreachable.ts │ ├── tailwind.config.js │ └── tsconfig.json ├── benchmarks └── tailwind-component │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── bench-results-100-iterations.json │ ├── package.json │ ├── src │ ├── benchmark-0.0.12-vs-local-version.ts │ ├── benchmark-0.0.15-vs-local-version.ts │ ├── benchmark-with-vs-without.ts │ ├── emails │ │ ├── with-tailwind.tsx │ │ └── without-tailwind.tsx │ └── tailwind-render.ts │ ├── tailwind.config.js │ └── tsconfig.json ├── examples ├── aws-ses │ ├── .babelrc │ ├── .eslintrc.js │ ├── package.json │ ├── src │ │ ├── email.tsx │ │ └── index.tsx │ └── tsconfig.json ├── mailersend │ ├── .babelrc │ ├── .eslintrc.js │ ├── package.json │ ├── src │ │ ├── email.tsx │ │ └── index.tsx │ └── tsconfig.json ├── nodemailer │ ├── .babelrc │ ├── .eslintrc.js │ ├── package.json │ ├── src │ │ ├── email.tsx │ │ └── index.tsx │ └── tsconfig.json ├── plunk │ ├── .babelrc │ ├── .eslintrc.js │ ├── package.json │ ├── src │ │ ├── email.tsx │ │ └── index.tsx │ └── tsconfig.json ├── postmark │ ├── .babelrc │ ├── .eslintrc.js │ ├── package.json │ ├── src │ │ ├── email.tsx │ │ └── index.tsx │ └── tsconfig.json ├── resend │ ├── next-env.d.ts │ ├── package.json │ ├── src │ │ ├── lib │ │ │ └── resend.ts │ │ └── pages │ │ │ └── api │ │ │ └── send.ts │ ├── transactional │ │ ├── emails │ │ │ └── waitlist.tsx │ │ ├── package.json │ │ └── readme.md │ └── tsconfig.json ├── scaleway │ ├── next │ │ ├── next-env.d.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── lib │ │ │ │ └── scaleway.ts │ │ │ └── pages │ │ │ │ └── api │ │ │ │ └── send.ts │ │ ├── transactional │ │ │ ├── emails │ │ │ │ └── waitlist.tsx │ │ │ ├── package.json │ │ │ └── readme.md │ │ └── tsconfig.json │ └── node │ │ ├── .babelrc │ │ ├── .eslintrc.js │ │ ├── package.json │ │ ├── src │ │ ├── email.tsx │ │ └── index.tsx │ │ └── tsconfig.json └── sendgrid │ ├── .babelrc │ ├── .eslintrc.js │ ├── package.json │ ├── src │ ├── email.tsx │ └── index.tsx │ └── tsconfig.json ├── package.json ├── packages ├── body │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── body.spec.tsx │ │ ├── body.tsx │ │ └── index.ts │ └── tsconfig.json ├── button │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── __snapshots__ │ │ │ └── button.spec.tsx.snap │ │ ├── button.spec.tsx │ │ ├── button.tsx │ │ ├── index.ts │ │ └── utils │ │ │ ├── index.ts │ │ │ ├── parse-padding.ts │ │ │ ├── px-to-pt.ts │ │ │ └── utils.spec.ts │ └── tsconfig.json ├── code-block │ ├── .babelrc │ ├── .eslintrc.js │ ├── .prettierignore │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── code-block.tsx │ │ ├── index.ts │ │ ├── languages-available.ts │ │ ├── prism.ts │ │ └── themes.ts │ └── tsconfig.json ├── code-inline │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── code-inline.tsx │ │ └── index.ts │ └── tsconfig.json ├── column │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── column.spec.tsx │ │ ├── column.tsx │ │ └── index.ts │ └── tsconfig.json ├── components │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── __snapshots__ │ │ │ └── heading.spec.tsx.snap │ │ └── index.ts │ └── tsconfig.json ├── container │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── container.spec.tsx │ │ ├── container.tsx │ │ └── index.ts │ └── tsconfig.json ├── create-email │ ├── .babelrc │ ├── .eslintrc.cjs │ ├── .npmignore │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── index.js │ │ └── tree.js │ ├── template │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── emails │ │ │ ├── notion-magic-link.tsx │ │ │ ├── plaid-verify-identity.tsx │ │ │ ├── static │ │ │ │ ├── notion-logo.png │ │ │ │ ├── plaid-logo.png │ │ │ │ ├── plaid.png │ │ │ │ ├── stripe-logo.png │ │ │ │ ├── vercel-arrow.png │ │ │ │ ├── vercel-logo.png │ │ │ │ ├── vercel-team.png │ │ │ │ └── vercel-user.png │ │ │ ├── stripe-welcome.tsx │ │ │ └── vercel-invite-user.tsx │ │ ├── package.json │ │ └── readme.md │ └── tsconfig.json ├── eslint-config-custom │ ├── README.md │ ├── library.js │ ├── next.js │ ├── package.json │ └── react-internal.js ├── font │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── font.spec.tsx │ │ ├── font.tsx │ │ └── index.ts │ └── tsconfig.json ├── head │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── head.spec.tsx │ │ ├── head.tsx │ │ └── index.ts │ └── tsconfig.json ├── heading │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── heading.spec.tsx │ │ ├── heading.tsx │ │ ├── index.ts │ │ └── utils │ │ │ ├── as.ts │ │ │ ├── index.ts │ │ │ ├── spaces.ts │ │ │ └── utils.spec.ts │ └── tsconfig.json ├── hr │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── hr.spec.tsx │ │ ├── hr.tsx │ │ └── index.ts │ └── tsconfig.json ├── html │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── html.spec.tsx │ │ ├── html.tsx │ │ └── index.ts │ └── tsconfig.json ├── img │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── img.spec.tsx │ │ ├── img.tsx │ │ └── index.ts │ └── tsconfig.json ├── link │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── index.ts │ │ ├── link.spec.tsx │ │ └── link.tsx │ └── tsconfig.json ├── markdown │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── __snapshots__ │ │ │ └── markdown.spec.tsx.snap │ │ ├── index.ts │ │ ├── markdown.spec.tsx │ │ └── markdown.tsx │ └── tsconfig.json ├── preview │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── index.ts │ │ ├── preview.spec.tsx │ │ └── preview.tsx │ └── tsconfig.json ├── react-email │ ├── .eslintrc.js │ ├── .gitignore │ ├── .npmignore │ ├── .prettierignore │ ├── .prettierrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── next-env.d.ts │ ├── next.config.js │ ├── package.json │ ├── postcss.config.js │ ├── readme.md │ ├── src │ │ ├── actions │ │ │ ├── get-email-path-from-slug.ts │ │ │ ├── get-emails-directory-metadata.spec.ts │ │ │ ├── get-emails-directory-metadata.ts │ │ │ └── render-email-by-path.tsx │ │ ├── app │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── inter.ts │ │ │ ├── layout.tsx │ │ │ ├── logo.png │ │ │ ├── page.tsx │ │ │ └── preview │ │ │ │ └── [...slug] │ │ │ │ ├── page.tsx │ │ │ │ ├── preview.tsx │ │ │ │ └── rendering-error.tsx │ │ ├── cli │ │ │ ├── commands │ │ │ │ ├── .npmignore │ │ │ │ ├── build.ts │ │ │ │ ├── dev.ts │ │ │ │ ├── export.ts │ │ │ │ ├── start.ts │ │ │ │ └── testing │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── export.spec.ts.snap │ │ │ │ │ └── export.spec.ts │ │ │ ├── index.ts │ │ │ └── utils │ │ │ │ ├── close-ora-on-sigint.ts │ │ │ │ ├── index.ts │ │ │ │ ├── preview │ │ │ │ ├── get-env-variables-for-preview-app.ts │ │ │ │ ├── hot-reloading │ │ │ │ │ ├── create-dependency-graph.spec.ts │ │ │ │ │ ├── create-dependency-graph.ts │ │ │ │ │ ├── get-imported-modules.spec.ts │ │ │ │ │ ├── get-imported-modules.ts │ │ │ │ │ └── setup-hot-reloading.ts │ │ │ │ ├── index.ts │ │ │ │ ├── serve-static-file.ts │ │ │ │ └── start-dev-server.ts │ │ │ │ ├── tree.spec.ts │ │ │ │ └── tree.ts │ │ ├── components │ │ │ ├── button.tsx │ │ │ ├── code-container.tsx │ │ │ ├── code.tsx │ │ │ ├── heading.tsx │ │ │ ├── icons │ │ │ │ ├── icon-arrow-down.tsx │ │ │ │ ├── icon-base.tsx │ │ │ │ ├── icon-button.tsx │ │ │ │ ├── icon-check.tsx │ │ │ │ ├── icon-clipboard.tsx │ │ │ │ ├── icon-download.tsx │ │ │ │ ├── icon-file.tsx │ │ │ │ ├── icon-folder-open.tsx │ │ │ │ ├── icon-folder.tsx │ │ │ │ ├── icon-hide-sidebar.tsx │ │ │ │ ├── icon-monitor.tsx │ │ │ │ ├── icon-phone.tsx │ │ │ │ └── icon-source.tsx │ │ │ ├── index.ts │ │ │ ├── logo.tsx │ │ │ ├── send.tsx │ │ │ ├── shell.tsx │ │ │ ├── sidebar │ │ │ │ ├── index.ts │ │ │ │ ├── sidebar-directory-children.tsx │ │ │ │ ├── sidebar-directory.tsx │ │ │ │ └── sidebar.tsx │ │ │ ├── text.tsx │ │ │ ├── tooltip-content.tsx │ │ │ ├── tooltip.tsx │ │ │ └── topbar.tsx │ │ ├── contexts │ │ │ └── emails.tsx │ │ ├── hooks │ │ │ ├── use-hot-reload.ts │ │ │ └── use-rendering-metadata.ts │ │ └── utils │ │ │ ├── __snapshots__ │ │ │ └── get-email-component.spec.ts.snap │ │ │ ├── cn.ts │ │ │ ├── constants.ts │ │ │ ├── copy-text-to-clipboard.ts │ │ │ ├── emails-directory-absolute-path.ts │ │ │ ├── esbuild │ │ │ ├── escape-string-for-regex.ts │ │ │ └── renderring-utilities-exporter.ts │ │ │ ├── get-email-component.spec.ts │ │ │ ├── get-email-component.ts │ │ │ ├── improve-error-with-sourcemap.ts │ │ │ ├── index.ts │ │ │ ├── language-map.ts │ │ │ ├── static-node-modules-for-vm.ts │ │ │ ├── types │ │ │ ├── as.ts │ │ │ ├── email-template.ts │ │ │ ├── error-object.ts │ │ │ ├── hot-reload-change.ts │ │ │ └── hot-reload-event.ts │ │ │ └── unreachable.ts │ ├── tailwind.config.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── render │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── browser │ │ │ ├── index.ts │ │ │ ├── render-async-web.spec.tsx │ │ │ └── render-async.ts │ │ ├── node │ │ │ ├── __snapshots__ │ │ │ │ └── render-async-node.spec.tsx.snap │ │ │ ├── index.ts │ │ │ ├── render-async-edge.spec.tsx │ │ │ ├── render-async-node.spec.tsx │ │ │ └── render-async.ts │ │ └── shared │ │ │ ├── options.ts │ │ │ ├── plain-text-selectors.ts │ │ │ ├── react-internals.d.ts │ │ │ ├── render.spec.tsx │ │ │ ├── render.ts │ │ │ └── utils │ │ │ ├── pretty.ts │ │ │ ├── preview.tsx │ │ │ └── template.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── row │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── index.ts │ │ ├── row.spec.tsx │ │ └── row.tsx │ └── tsconfig.json ├── section │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── index.ts │ │ ├── section.spec.tsx │ │ └── section.tsx │ └── tsconfig.json ├── tailwind │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── __snapshots__ │ │ │ └── tailwind.spec.tsx.snap │ │ ├── hooks │ │ │ ├── use-style-inlining.ts │ │ │ ├── use-tailwind-styles.spec.tsx │ │ │ └── use-tailwind-styles.tsx │ │ ├── index.ts │ │ ├── tailwind.spec.tsx │ │ ├── tailwind.tsx │ │ └── utils │ │ │ ├── __snapshots__ │ │ │ └── quick-safe-render-to-string.spec.tsx.snap │ │ │ ├── compatibility │ │ │ ├── css-to-jsx-style.spec.ts │ │ │ ├── css-to-jsx-style.ts │ │ │ ├── escape-class-name.spec.ts │ │ │ ├── escape-class-name.ts │ │ │ ├── make-all-rule-properties-important.ts │ │ │ ├── sanitize-class-name.spec.ts │ │ │ ├── sanitize-class-name.ts │ │ │ ├── sanitize-rule-selector.ts │ │ │ ├── unescape-class.ts │ │ │ ├── use-rgb-non-spaced-syntax.spec.ts │ │ │ └── use-rgb-non-spaced-syntax.ts │ │ │ ├── css │ │ │ ├── media-queries │ │ │ │ ├── separate-media-queries-from-css.spec.ts │ │ │ │ └── separate-media-queries-from-css.ts │ │ │ ├── minify-css.ts │ │ │ └── rules-for.ts │ │ │ ├── quick-safe-render-to-string.spec.tsx │ │ │ ├── quick-safe-render-to-string.ts │ │ │ └── tailwindcss │ │ │ ├── get-css-for-markup.spec.tsx │ │ │ └── get-css-for-markup.ts │ ├── tsconfig.json │ └── vite.config.ts ├── text │ ├── .babelrc │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── license.md │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── index.ts │ │ ├── text.spec.tsx │ │ └── text.tsx │ └── tsconfig.json └── tsconfig │ ├── base.json │ ├── nextjs.json │ ├── package.json │ └── react-library.json ├── patches ├── postcss-css-variables@0.19.0.patch ├── process@0.11.10.patch └── tailwindcss@3.3.2.patch ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── renovate.json ├── tsconfig.json ├── turbo.json ├── vitest.config.ts └── vitest.workspace.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [ 6 | ["react-email-starter", "create-email"] 7 | ], 8 | "linked": [], 9 | "access": "public", 10 | "baseBranch": "main", 11 | "updateInternalDependencies": "patch", 12 | "ignore": [ 13 | "@benchmarks/tailwind-component", 14 | "demo", 15 | "web" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.changeset/curly-fireants-allow.md: -------------------------------------------------------------------------------- 1 | --- 2 | "react-email": patch 3 | --- 4 | 5 | Fixes decorators causing dependency tree babel parsing to fail 6 | -------------------------------------------------------------------------------- /.changeset/dry-humans-return.md: -------------------------------------------------------------------------------- 1 | --- 2 | "react-email": patch 3 | --- 4 | 5 | update socket.io/socket.io-client to 4.7.5 6 | -------------------------------------------------------------------------------- /.changeset/fast-countries-marry.md: -------------------------------------------------------------------------------- 1 | --- 2 | "create-email": patch 3 | "@react-email/code-inline": patch 4 | "react-email": patch 5 | "@react-email/code-block": patch 6 | "@react-email/components": patch 7 | "@react-email/container": patch 8 | "@react-email/markdown": patch 9 | "@react-email/tailwind": patch 10 | "@react-email/heading": patch 11 | "@react-email/preview": patch 12 | "@react-email/section": patch 13 | "@react-email/button": patch 14 | "@react-email/column": patch 15 | "@react-email/render": patch 16 | "@react-email/body": patch 17 | "@react-email/font": patch 18 | "@react-email/head": patch 19 | "@react-email/html": patch 20 | "@react-email/link": patch 21 | "@react-email/text": patch 22 | "@react-email/img": patch 23 | "@react-email/row": patch 24 | "@react-email/hr": patch 25 | --- 26 | 27 | Updated peer dependencies to allow for React 19 release candidated and React 19 itself 28 | -------------------------------------------------------------------------------- /.changeset/many-donuts-retire.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@react-email/tailwind": minor 3 | --- 4 | 5 | - Add support for proper `className` manipulation 6 | - Make inline styles override Tailwind styles. 7 | -------------------------------------------------------------------------------- /.changeset/new-coats-cover.md: -------------------------------------------------------------------------------- 1 | --- 2 | "react-email": patch 3 | --- 4 | 5 | Fixes tooltip color being black for specific theming configurations 6 | -------------------------------------------------------------------------------- /.changeset/odd-bobcats-know.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@react-email/button": patch 3 | --- 4 | 5 | Add missing `msoPaddingAlt` to containing `` tag 6 | -------------------------------------------------------------------------------- /.changeset/old-suits-promise.md: -------------------------------------------------------------------------------- 1 | --- 2 | "react-email": patch 3 | --- 4 | 5 | Fixes root directories being hidden when they are alone at their depth 6 | -------------------------------------------------------------------------------- /.changeset/tame-windows-look.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@react-email/tailwind": patch 3 | --- 4 | 5 | Fixes generation of unecessary styles (ex: including `container` as text somehwere in your template) 6 | -------------------------------------------------------------------------------- /.changeset/wild-mugs-kick.md: -------------------------------------------------------------------------------- 1 | --- 2 | "react-email-starter": patch 3 | --- 4 | 5 | add react-dom as a template dependency as well 6 | -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/help.yml: -------------------------------------------------------------------------------- 1 | body: 2 | - type: textarea 3 | attributes: 4 | label: Summary 5 | description: What do you need help with? 6 | validations: 7 | required: true 8 | - type: textarea 9 | attributes: 10 | label: Additional information 11 | description: Any code snippets, error messages, or dependency details that may be related? 12 | render: js 13 | validations: 14 | required: false 15 | - type: input 16 | attributes: 17 | label: Example 18 | description: A link to a minimal reproduction is helpful for collaborative debugging! 19 | validations: 20 | required: false 21 | -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/ideas.yml: -------------------------------------------------------------------------------- 1 | body: 2 | - type: textarea 3 | attributes: 4 | label: Goals 5 | description: Short list of what the feature request aims to address? 6 | value: | 7 | 1. 8 | 2. 9 | 3. 10 | validations: 11 | required: true 12 | - type: textarea 13 | attributes: 14 | label: Background 15 | description: Discuss prior art, why do you think this feature is needed? Are there current alternatives? 16 | validations: 17 | required: true 18 | - type: textarea 19 | attributes: 20 | label: Proposal 21 | description: How should this feature be implemented? Are you interested in contributing? 22 | validations: 23 | required: true 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/resend/react-email/discussions 5 | about: Ask questions and discuss with other community members 6 | - name: Feature request 7 | url: https://github.com/resend/react-email/discussions/new?category=ideas 8 | about: Feature requests should be opened as discussions 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | dist 16 | .vercel 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | .react-email 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | .pnpm-debug.log* 28 | 29 | # local env files 30 | .env 31 | .env.local 32 | .env.development.local 33 | .env.test.local 34 | .env.production.local 35 | 36 | # turbo 37 | .turbo 38 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers = true 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /apps/demo/.gitignore: -------------------------------------------------------------------------------- 1 | .react-email 2 | .vercel 3 | -------------------------------------------------------------------------------- /apps/demo/emails/static/airbnb-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/airbnb-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/airbnb-review-user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/airbnb-review-user.jpg -------------------------------------------------------------------------------- /apps/demo/emails/static/amazon-book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/amazon-book.jpg -------------------------------------------------------------------------------- /apps/demo/emails/static/amazon-facebook.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/amazon-facebook.jpg -------------------------------------------------------------------------------- /apps/demo/emails/static/amazon-instagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/amazon-instagram.jpg -------------------------------------------------------------------------------- /apps/demo/emails/static/amazon-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/amazon-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/amazon-prime-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/amazon-prime-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/amazon-rating.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/amazon-rating.gif -------------------------------------------------------------------------------- /apps/demo/emails/static/amazon-twitter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/amazon-twitter.jpg -------------------------------------------------------------------------------- /apps/demo/emails/static/apple-card-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/apple-card-icon.png -------------------------------------------------------------------------------- /apps/demo/emails/static/apple-hbo-max-icon.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/apple-hbo-max-icon.jpeg -------------------------------------------------------------------------------- /apps/demo/emails/static/apple-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/apple-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/apple-wallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/apple-wallet.png -------------------------------------------------------------------------------- /apps/demo/emails/static/aws-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/aws-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/codepen-challengers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/codepen-challengers.png -------------------------------------------------------------------------------- /apps/demo/emails/static/codepen-cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/codepen-cube.png -------------------------------------------------------------------------------- /apps/demo/emails/static/codepen-pro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/codepen-pro.png -------------------------------------------------------------------------------- /apps/demo/emails/static/dropbox-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/dropbox-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/github.png -------------------------------------------------------------------------------- /apps/demo/emails/static/google-play-academy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/google-play-academy.png -------------------------------------------------------------------------------- /apps/demo/emails/static/google-play-chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/google-play-chat.png -------------------------------------------------------------------------------- /apps/demo/emails/static/google-play-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/google-play-footer.png -------------------------------------------------------------------------------- /apps/demo/emails/static/google-play-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/google-play-header.png -------------------------------------------------------------------------------- /apps/demo/emails/static/google-play-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/google-play-icon.png -------------------------------------------------------------------------------- /apps/demo/emails/static/google-play-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/google-play-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/google-play-pl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/google-play-pl.png -------------------------------------------------------------------------------- /apps/demo/emails/static/google-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/google-play.png -------------------------------------------------------------------------------- /apps/demo/emails/static/koala-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/koala-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/linear-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/linear-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/netlify-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/netlify-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/nike-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/nike-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/nike-phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/nike-phone.png -------------------------------------------------------------------------------- /apps/demo/emails/static/nike-product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/nike-product.png -------------------------------------------------------------------------------- /apps/demo/emails/static/nike-recomendation-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/nike-recomendation-1.png -------------------------------------------------------------------------------- /apps/demo/emails/static/nike-recomendation-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/nike-recomendation-2.png -------------------------------------------------------------------------------- /apps/demo/emails/static/nike-recomendation-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/nike-recomendation-3.png -------------------------------------------------------------------------------- /apps/demo/emails/static/nike-recomendation-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/nike-recomendation-4.png -------------------------------------------------------------------------------- /apps/demo/emails/static/notion-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/notion-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/plaid-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/plaid-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/raycast-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/raycast-bg.png -------------------------------------------------------------------------------- /apps/demo/emails/static/raycast-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/raycast-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/slack-facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/slack-facebook.png -------------------------------------------------------------------------------- /apps/demo/emails/static/slack-linkedin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/slack-linkedin.png -------------------------------------------------------------------------------- /apps/demo/emails/static/slack-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/slack-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/slack-twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/slack-twitter.png -------------------------------------------------------------------------------- /apps/demo/emails/static/stack-overflow-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/stack-overflow-header.png -------------------------------------------------------------------------------- /apps/demo/emails/static/stack-overflow-logo-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/stack-overflow-logo-sm.png -------------------------------------------------------------------------------- /apps/demo/emails/static/stack-overflow-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/stack-overflow-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/stripe-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/stripe-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/twitch-icon-facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/twitch-icon-facebook.png -------------------------------------------------------------------------------- /apps/demo/emails/static/twitch-icon-twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/twitch-icon-twitter.png -------------------------------------------------------------------------------- /apps/demo/emails/static/twitch-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/twitch-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/vercel-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/vercel-arrow.png -------------------------------------------------------------------------------- /apps/demo/emails/static/vercel-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/vercel-logo.png -------------------------------------------------------------------------------- /apps/demo/emails/static/vercel-team.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/vercel-team.png -------------------------------------------------------------------------------- /apps/demo/emails/static/vercel-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/vercel-user.png -------------------------------------------------------------------------------- /apps/demo/emails/static/yelp-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/yelp-footer.png -------------------------------------------------------------------------------- /apps/demo/emails/static/yelp-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/yelp-header.png -------------------------------------------------------------------------------- /apps/demo/emails/static/yelp-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/demo/emails/static/yelp-logo.png -------------------------------------------------------------------------------- /apps/demo/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /apps/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "pnpm install --frozen-lockfile && email build", 7 | "dev": "email dev", 8 | "start": "email start", 9 | "export": "email export" 10 | }, 11 | "dependencies": { 12 | "@react-email/components": "workspace:*", 13 | "react": "19.0.0-rc.0", 14 | "react-dom": "19.0.0-rc.0", 15 | "react-email": "workspace:*" 16 | }, 17 | "devDependencies": { 18 | "next": "14.2.3", 19 | "@types/react": "npm:types-react@rc", 20 | "@types/react-dom": "npm:types-react-dom@rc", 21 | "tsx": "4.9.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/docs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/docs/favicon.png -------------------------------------------------------------------------------- /apps/docs/getting-started/monorepo-setup/choose-package-manager.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Monorepo setup' 3 | sidebarTitle: 'bun' 4 | 'og:image': 'https://react.email/static/covers/react-email.png' 5 | --- 6 | 7 | What package manager are you using? 8 | 9 | 10 | 11 | See a manual setup guide specific for npm 12 | 13 | 14 | See a manual setup guide specific for pnpm 15 | 16 | 17 | See a manual setup guide specific for yarn 18 | 19 | 20 | See a manual setup guide specific for bun 21 | 22 | 23 | -------------------------------------------------------------------------------- /apps/docs/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/docs/images/background.png -------------------------------------------------------------------------------- /apps/docs/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/docs/images/bg.png -------------------------------------------------------------------------------- /apps/docs/images/local-dev.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/docs/images/local-dev.jpg -------------------------------------------------------------------------------- /apps/docs/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "install": "mintlify install", 7 | "dev": "mintlify dev" 8 | }, 9 | "dependencies": { 10 | "mintlify": "4.0.112" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /apps/docs/roadmap.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Roadmap' 3 | sidebarTitle: 'Roadmap' 4 | description: 'Understand what is currently being prioritized and what we are planning to build in the near future.' 5 | 'og:image': 'https://react.email/static/covers/react-email.png' 6 | icon: 'map' 7 | --- 8 | 9 | If any of these are important to you please let us know. We use community feedback to plan our roadmap, and we also encourage contributors to submit their ideas on [Discord](https://react.email/discord) so that we can discuss them with the community. 10 | 11 | Feel free to contribute to any of them as well. 12 | 13 | ## Planned Features 14 | 15 | These are the features that we've planned to work on in the near future. 16 | 17 | ### VS Code extension 18 | 19 | Build a VS Code extension where developers can build the email using React on one side and see a live preview right next to it. 20 | 21 | - [GitHub Discussion #574](https://github.com/resend/react-email/discussions/574) 22 | -------------------------------------------------------------------------------- /apps/docs/snippets/localdev.mdx: -------------------------------------------------------------------------------- 1 | 1. Clone the repository: 2 | 3 | ```sh 4 | git clone https://github.com/resend/react-email.git 5 | ``` 6 | 7 | 2. Install all dependencies: 8 | 9 | ```sh 10 | pnpm install 11 | ``` 12 | 13 | 3. Run local servers and watch for changes: 14 | 15 | ```sh 16 | pnpm dev 17 | ``` 18 | -------------------------------------------------------------------------------- /apps/docs/snippets/next-steps.mdx: -------------------------------------------------------------------------------- 1 | Try adding these other components to your email. 2 | 3 | 4 | 5 | Display an image in your email. 6 | 7 | 8 | A hyperlink to web pages or anything else a URL can address. 9 | 10 | 11 | Display a divider that separates content areas in your email. 12 | 13 | 18 | A preview text that will be displayed in the inbox of the recipient. 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /apps/web/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/next"], 3 | rules: { 4 | "eslint-comments/require-description": "off", 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /apps/web/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /apps/web/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/colors": "1.0.1", 13 | "@radix-ui/react-slot": "1.1.0", 14 | "@sindresorhus/is": "6.1.0", 15 | "@supabase/supabase-js": "2.39.3", 16 | "@vercel/analytics": "1.0.1", 17 | "classnames": "2.3.2", 18 | "next": "15.0.0-canary.27", 19 | "prism-react-renderer": "2.1.0", 20 | "react": "19.0.0-rc.0", 21 | "react-dom": "19.0.0-rc.0", 22 | "resend": "3.5.0" 23 | }, 24 | "devDependencies": { 25 | "@next/eslint-plugin-next": "14.2.3", 26 | "autoprefixer": "10.4.14", 27 | "eslint-config-custom": "workspace:*", 28 | "postcss": "8.4.40", 29 | "tailwindcss": "3.4.3", 30 | "tsconfig": "workspace:*", 31 | "typescript": "5.1.6" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /apps/web/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/web/public/static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/web/public/static/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/bg.png -------------------------------------------------------------------------------- /apps/web/public/static/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/cover.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/button.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/code-block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/code-block.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/code-inline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/code-inline.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/column.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/column.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/components.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/container.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/create-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/create-email.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/font.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/head.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/heading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/heading.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/hr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/hr.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/html.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/img.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/link.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/markdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/markdown.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/preview.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/react-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/react-email.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/render.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/row.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/row.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/section.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/section.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/tailwind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/tailwind.png -------------------------------------------------------------------------------- /apps/web/public/static/covers/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/covers/text.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/airbnb-review.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/airbnb-review.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/apple-receipt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/apple-receipt.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/aws-verify-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/aws-verify-email.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/dropbox-reset-password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/dropbox-reset-password.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/github-access-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/github-access-token.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/google-play-policy-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/google-play-policy-update.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/koala-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/koala-welcome.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/linear-login-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/linear-login-code.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/nike-receipt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/nike-receipt.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/notion-magic-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/notion-magic-link.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/plaid-verify-identity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/plaid-verify-identity.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/raycast-magic-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/raycast-magic-link.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/slack-confirm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/slack-confirm.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/stack-overflow-tips.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/stack-overflow-tips.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/stripe-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/stripe-welcome.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/twitch-reset-password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/twitch-reset-password.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/vercel-invite-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/vercel-invite-user.png -------------------------------------------------------------------------------- /apps/web/public/static/examples/yelp-recent-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/examples/yelp-recent-login.png -------------------------------------------------------------------------------- /apps/web/public/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/favicon.ico -------------------------------------------------------------------------------- /apps/web/public/static/icons/gmail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /apps/web/public/static/icons/yahoo-mail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/web/public/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/logo.png -------------------------------------------------------------------------------- /apps/web/public/static/resend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/apps/web/public/static/resend.png -------------------------------------------------------------------------------- /apps/web/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /apps/web/src/app/inter.ts: -------------------------------------------------------------------------------- 1 | import { Inter } from "next/font/google"; 2 | 3 | export const inter = Inter({ 4 | subsets: ["latin"], 5 | weight: ["400", "500", "700"], 6 | variable: "--font-inter", 7 | }); 8 | -------------------------------------------------------------------------------- /apps/web/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import * as React from "react"; 3 | import { Anchor } from "./anchor"; 4 | import { Text } from "./text"; 5 | 6 | export const Footer: React.FC = () => ( 7 |
8 | 9 | Brought to you by{" "} 10 | 16 | 23 | Resend 24 | 25 | 26 |
27 | ); 28 | -------------------------------------------------------------------------------- /apps/web/src/components/icon-button.tsx: -------------------------------------------------------------------------------- 1 | import classnames from "classnames"; 2 | import * as React from "react"; 3 | 4 | export type IconButtonProps = React.ComponentPropsWithoutRef<"button">; 5 | 6 | export const IconButton: React.FC> = ({ 7 | children, 8 | className, 9 | ...props 10 | }) => ( 11 | 21 | ); 22 | -------------------------------------------------------------------------------- /apps/web/src/components/icons/icon-arrow-right.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import type { IconProps } from "./icon-base"; 3 | import { IconBase } from "./icon-base"; 4 | 5 | export const IconArrowRight: React.FC> = (props) => ( 6 | 7 | 14 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /apps/web/src/components/icons/icon-base.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface IconProps extends React.ComponentPropsWithoutRef<"svg"> { 4 | size?: number; 5 | } 6 | 7 | export const IconBase: React.FC = ({ size = 20, ...props }) => ( 8 | 16 | ); 17 | -------------------------------------------------------------------------------- /apps/web/src/components/icons/icon-check.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import type { IconProps } from "./icon-base"; 3 | import { IconBase } from "./icon-base"; 4 | 5 | export const IconCheck: React.FC> = (props) => ( 6 | 7 | 14 | 15 | ); 16 | -------------------------------------------------------------------------------- /apps/web/src/components/icons/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./icon-arrow-right"; 2 | export * from "./icon-check"; 3 | export * from "./icon-clipboard"; 4 | -------------------------------------------------------------------------------- /apps/web/src/components/topbar.tsx: -------------------------------------------------------------------------------- 1 | import classnames from "classnames"; 2 | import Link from "next/link"; 3 | import * as React from "react"; 4 | import { Logo } from "./logo"; 5 | import { Menu } from "./menu"; 6 | 7 | type RootProps = React.ComponentPropsWithoutRef<"header">; 8 | 9 | type TopbarProps = RootProps; 10 | 11 | export const Topbar: React.FC> = ({ 12 | className, 13 | ...props 14 | }) => ( 15 |
22 |
23 | 24 | 25 | 26 |
27 | 28 |
29 | ); 30 | -------------------------------------------------------------------------------- /apps/web/src/utils/as.ts: -------------------------------------------------------------------------------- 1 | export type As< 2 | DefaultTag extends React.ElementType, 3 | T1 extends React.ElementType, 4 | T2 extends React.ElementType = T1, 5 | T3 extends React.ElementType = T1, 6 | T4 extends React.ElementType = T1, 7 | T5 extends React.ElementType = T1, 8 | > = 9 | | (React.ComponentPropsWithRef & { 10 | as?: DefaultTag; 11 | }) 12 | | (React.ComponentPropsWithRef & { 13 | as: T1; 14 | }) 15 | | (React.ComponentPropsWithRef & { 16 | as: T2; 17 | }) 18 | | (React.ComponentPropsWithRef & { 19 | as: T3; 20 | }) 21 | | (React.ComponentPropsWithRef & { 22 | as: T4; 23 | }) 24 | | (React.ComponentPropsWithRef & { 25 | as: T5; 26 | }); 27 | -------------------------------------------------------------------------------- /apps/web/src/utils/unreachable.ts: -------------------------------------------------------------------------------- 1 | export const unreachable = ( 2 | condition: never, 3 | message = `Entered unreachable code. Received '${ 4 | typeof condition === "string" ? condition : JSON.stringify(condition) 5 | }'.`, 6 | ): never => { 7 | throw new TypeError(message); 8 | }; 9 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [{ "name": "next" }] 5 | }, 6 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /benchmarks/tailwind-component/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['custom/react-internal'], 3 | rules: { 4 | 'eslint-comments/require-description': 'off', 5 | 'no-console': 'off', 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /benchmarks/tailwind-component/.gitignore: -------------------------------------------------------------------------------- 1 | isolate-*.log 2 | flamegraph.html 3 | .preview 4 | .vscpreview 5 | -------------------------------------------------------------------------------- /benchmarks/tailwind-component/src/benchmark-0.0.12-vs-local-version.ts: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/render"; 2 | import { writeFileSync } from "fs"; 3 | import { Bench } from "tinybench"; 4 | import EmailWithTailwind from "./emails/with-tailwind.js"; 5 | import { Tailwind as LocalTailwind } from "@react-email/tailwind"; 6 | import { Tailwind as VersionTwelveTailwind } from "tailwind-0.0.12"; 7 | 8 | const main = async () => { 9 | const bench = new Bench({ 10 | iterations: 100, 11 | }); 12 | 13 | bench 14 | .add("local", () => { 15 | render(EmailWithTailwind({ Tailwind: LocalTailwind })); 16 | }) 17 | .add("0.0.12", () => { 18 | render(EmailWithTailwind({ Tailwind: VersionTwelveTailwind })); 19 | }); 20 | 21 | await bench.run(); 22 | 23 | return bench; 24 | }; 25 | 26 | main() 27 | .then((bench) => { 28 | writeFileSync( 29 | "bench-results-100-iterations.json", 30 | JSON.stringify(bench.results), 31 | "utf-8", 32 | ); 33 | console.table(bench.table()); 34 | }) 35 | .catch(console.error); 36 | -------------------------------------------------------------------------------- /benchmarks/tailwind-component/src/benchmark-0.0.15-vs-local-version.ts: -------------------------------------------------------------------------------- 1 | import { writeFileSync } from "node:fs"; 2 | import { render } from "@react-email/render"; 3 | import { Bench } from "tinybench"; 4 | import { Tailwind as VersionFifteenTailwind } from "tailwind-0.0.15"; 5 | import { Tailwind as LocalTailwind } from "@react-email/tailwind"; 6 | import EmailWithTailwind from "./emails/with-tailwind.js"; 7 | 8 | const main = async () => { 9 | const bench = new Bench({ 10 | iterations: 100, 11 | }); 12 | 13 | bench 14 | .add("local", () => { 15 | render(EmailWithTailwind({ Tailwind: LocalTailwind })); 16 | }) 17 | .add("0.0.15", () => { 18 | render(EmailWithTailwind({ Tailwind: VersionFifteenTailwind })); 19 | }); 20 | 21 | await bench.run(); 22 | 23 | return bench; 24 | }; 25 | 26 | main() 27 | .then((bench) => { 28 | writeFileSync( 29 | "bench-results-100-iterations.json", 30 | JSON.stringify(bench.results), 31 | "utf-8", 32 | ); 33 | console.table(bench.table()); 34 | }) 35 | .catch(console.error); 36 | -------------------------------------------------------------------------------- /benchmarks/tailwind-component/src/benchmark-with-vs-without.ts: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/render"; 2 | import { Bench } from "tinybench"; 3 | import EmailWithoutTailwind from "./emails/without-tailwind.js"; 4 | import EmailWithTailwind from "./emails/with-tailwind.js"; 5 | 6 | // import like this instead of installing from the workspace 7 | // to still be able to test versions that are already published 8 | import { Tailwind as CurrentTailwind } from "../../../packages/tailwind/dist"; 9 | 10 | async function main() { 11 | const bench = new Bench({ time: 100 }); 12 | 13 | bench 14 | .add("without tailwind", () => { 15 | render(EmailWithoutTailwind()); 16 | }) 17 | .add("with current tailwind", () => { 18 | render(EmailWithTailwind({ Tailwind: CurrentTailwind })); 19 | }); 20 | 21 | await bench.run(); 22 | 23 | return bench; 24 | } 25 | 26 | main() 27 | .then((bench) => { 28 | console.table(bench.table()); 29 | }) 30 | .catch(console.error); 31 | -------------------------------------------------------------------------------- /benchmarks/tailwind-component/src/tailwind-render.ts: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/render"; 2 | import { Tailwind as CurrentTailwind } from "../../../packages/tailwind/dist"; 3 | import EmailWithTailwind from "./emails/with-tailwind.js"; 4 | 5 | render(EmailWithTailwind({ Tailwind: CurrentTailwind })); 6 | -------------------------------------------------------------------------------- /benchmarks/tailwind-component/tailwind.config.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/benchmarks/tailwind-component/tailwind.config.js -------------------------------------------------------------------------------- /benchmarks/tailwind-component/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "tsconfig/react-library.json", 4 | "include": ["src"], 5 | "exclude": ["dist", "build", "node_modules"], 6 | "compilerOptions": { 7 | "target": "esnext", 8 | "noUncheckedIndexedAccess": true, 9 | "resolveJsonModule": true, 10 | "moduleResolution": "Node", 11 | "declarationMap": false, 12 | "declaration": false, 13 | "outDir": "dist" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/aws-ses/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/aws-ses/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['custom'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/aws-ses/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-with-aws-ses", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "sideEffects": false, 7 | "main": "./dist/index.js", 8 | "module": "./dist/index.mjs", 9 | "types": "./dist/index.d.ts", 10 | "files": [ 11 | "dist/**" 12 | ], 13 | "scripts": { 14 | "build": "tsup src/index.tsx --format esm,cjs --dts --external react", 15 | "dev": "tsup src/index.tsx --format esm,cjs --dts --external react --watch", 16 | "clean": "rm -rf dist" 17 | }, 18 | "dependencies": { 19 | "@aws-sdk/client-ses": "3.341.0", 20 | "@react-email/components": "*", 21 | "react": "19.0.0-rc.0" 22 | }, 23 | "devDependencies": { 24 | "tsup": "6.2.3", 25 | "typescript": "4.8.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/aws-ses/src/email.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Html, Button } from "@react-email/components"; 3 | 4 | interface EmailProps { 5 | url: string; 6 | } 7 | 8 | export const Email: React.FC> = ({ url }) => { 9 | return ( 10 | 11 | 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /examples/aws-ses/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { SES } from "@aws-sdk/client-ses"; 2 | import { render } from "@react-email/components"; 3 | import { Email } from "./email"; 4 | 5 | // eslint-disable-next-line turbo/no-undeclared-env-vars 6 | const ses = new SES({ region: process.env.AWS_SES_REGION }); 7 | 8 | const emailHtml = render(); 9 | 10 | const params = { 11 | Source: "you@example.com", 12 | Destination: { 13 | ToAddresses: ["user@gmail.com"], 14 | }, 15 | Message: { 16 | Body: { 17 | Html: { 18 | Charset: "UTF-8", 19 | Data: emailHtml, 20 | }, 21 | }, 22 | Subject: { 23 | Charset: "UTF-8", 24 | Data: "hello world", 25 | }, 26 | }, 27 | }; 28 | 29 | ses.sendEmail(params); 30 | -------------------------------------------------------------------------------- /examples/aws-ses/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "inlineSources": false, 9 | "isolatedModules": true, 10 | "moduleResolution": "node", 11 | "noUnusedLocals": false, 12 | "noUnusedParameters": false, 13 | "preserveWatchOutput": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "strictNullChecks": true, 17 | "jsx": "react-jsx", 18 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 19 | "module": "ESNext", 20 | "target": "es6", 21 | "types": ["vitest/globals"] 22 | }, 23 | "include": ["."], 24 | "exclude": ["dist", "build", "node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /examples/mailersend/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/mailersend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['custom'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/mailersend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-with-mailersend", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "sideEffects": false, 7 | "main": "./dist/index.js", 8 | "module": "./dist/index.mjs", 9 | "types": "./dist/index.d.ts", 10 | "files": [ 11 | "dist/**" 12 | ], 13 | "scripts": { 14 | "build": "tsup src/index.tsx --format esm,cjs --dts --external react", 15 | "dev": "tsup src/index.tsx --format esm,cjs --dts --external react --watch", 16 | "clean": "rm -rf dist" 17 | }, 18 | "dependencies": { 19 | "@react-email/components": "*", 20 | "mailersend": "^2.0.0", 21 | "react": "19.0.0-rc.0" 22 | }, 23 | "devDependencies": { 24 | "tsup": "6.2.3", 25 | "typescript": "4.8.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/mailersend/src/email.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Button } from "@react-email/components"; 2 | 3 | interface EmailProps { 4 | url: string; 5 | } 6 | 7 | export const Email: React.FC> = ({ url }) => { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /examples/mailersend/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/components"; 2 | import { MailerSend, EmailParams, Sender, Recipient } from "mailersend"; 3 | import { Email } from "./email"; 4 | 5 | const mailerSend = new MailerSend({ 6 | apiKey: process.env.MAILERSEND_API_KEY || "", 7 | }); 8 | 9 | const emailHtml = render(); 10 | 11 | const sentFrom = new Sender("you@yourdomain.com", "Your name"); 12 | const recipients = [new Recipient("your@client.com", "Your Client")]; 13 | 14 | const emailParams = new EmailParams() 15 | .setFrom(sentFrom) 16 | .setTo(recipients) 17 | .setSubject("This is a Subject") 18 | .setHtml(emailHtml); 19 | 20 | mailerSend.email.send(emailParams); 21 | -------------------------------------------------------------------------------- /examples/mailersend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "inlineSources": false, 9 | "isolatedModules": true, 10 | "moduleResolution": "node", 11 | "noUnusedLocals": false, 12 | "noUnusedParameters": false, 13 | "preserveWatchOutput": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "strictNullChecks": true, 17 | "jsx": "react-jsx", 18 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 19 | "module": "ESNext", 20 | "target": "es6", 21 | "types": ["vitest/globals"] 22 | }, 23 | "include": ["."], 24 | "exclude": ["dist", "build", "node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /examples/nodemailer/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/nodemailer/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['custom'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/nodemailer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-with-nodemailer", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "sideEffects": false, 7 | "main": "./dist/index.js", 8 | "module": "./dist/index.mjs", 9 | "types": "./dist/index.d.ts", 10 | "files": [ 11 | "dist/**" 12 | ], 13 | "scripts": { 14 | "build": "tsup src/index.tsx --format esm,cjs --dts --external react", 15 | "dev": "tsup src/index.tsx --format esm,cjs --dts --external react --watch", 16 | "clean": "rm -rf dist" 17 | }, 18 | "dependencies": { 19 | "@react-email/components": "*", 20 | "nodemailer": "6.9.9", 21 | "react": "19.0.0-rc.0" 22 | }, 23 | "devDependencies": { 24 | "tsup": "6.2.3", 25 | "typescript": "4.8.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/nodemailer/src/email.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Button } from "@react-email/components"; 2 | 3 | interface EmailProps { 4 | url: string; 5 | } 6 | 7 | export const Email: React.FC> = ({ url }) => { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /examples/nodemailer/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/components"; 2 | import nodemailer from "nodemailer"; 3 | import { Email } from "./email"; 4 | 5 | const transporter = nodemailer.createTransport({ 6 | host: "smtp.forwardemail.net", 7 | port: 465, 8 | secure: true, 9 | auth: { 10 | user: "my_user", 11 | pass: "my_password", 12 | }, 13 | }); 14 | 15 | const emailHtml = render(); 16 | 17 | const options = { 18 | from: "you@example.com", 19 | to: "user@gmail.com", 20 | subject: "hello world", 21 | html: emailHtml, 22 | }; 23 | 24 | await transporter.sendMail(options); 25 | -------------------------------------------------------------------------------- /examples/nodemailer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "inlineSources": false, 9 | "isolatedModules": true, 10 | "moduleResolution": "node", 11 | "noUnusedLocals": false, 12 | "noUnusedParameters": false, 13 | "preserveWatchOutput": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "strictNullChecks": true, 17 | "jsx": "react-jsx", 18 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 19 | "module": "ESNext", 20 | "target": "es6", 21 | "types": ["vitest/globals"] 22 | }, 23 | "include": ["."], 24 | "exclude": ["dist", "build", "node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /examples/plunk/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/plunk/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['custom'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/plunk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-with-plunk", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "sideEffects": false, 7 | "main": "./dist/index.js", 8 | "module": "./dist/index.mjs", 9 | "types": "./dist/index.d.ts", 10 | "files": [ 11 | "dist/**" 12 | ], 13 | "scripts": { 14 | "build": "tsup src/index.tsx --format esm,cjs --dts --external react", 15 | "dev": "tsup src/index.tsx --format esm,cjs --dts --external react --watch", 16 | "clean": "rm -rf dist" 17 | }, 18 | "dependencies": { 19 | "@plunk/node": "1.1.1", 20 | "@react-email/components": "*", 21 | "react": "19.0.0-rc.0" 22 | }, 23 | "devDependencies": { 24 | "tsup": "6.2.3", 25 | "typescript": "4.8.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/plunk/src/email.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Button } from "@react-email/components"; 2 | 3 | interface EmailProps { 4 | url: string; 5 | } 6 | 7 | export const Email: React.FC> = ({ url }) => { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /examples/plunk/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/components"; 2 | import Plunk from "@plunk/node"; 3 | import { Email } from "./email"; 4 | 5 | // eslint-disable-next-line turbo/no-undeclared-env-vars 6 | const plunk = new Plunk(process.env.PLUNK_API_KEY || ""); 7 | 8 | const emailHtml = render(); 9 | 10 | plunk.emails.send({ 11 | to: "hello@useplunk.com", 12 | subject: "Hello world", 13 | body: emailHtml, 14 | }); 15 | -------------------------------------------------------------------------------- /examples/plunk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "inlineSources": false, 9 | "isolatedModules": true, 10 | "moduleResolution": "node", 11 | "noUnusedLocals": false, 12 | "noUnusedParameters": false, 13 | "preserveWatchOutput": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "strictNullChecks": true, 17 | "jsx": "react-jsx", 18 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 19 | "module": "ESNext", 20 | "target": "es6", 21 | "types": ["vitest/globals"] 22 | }, 23 | "include": ["."], 24 | "exclude": ["dist", "build", "node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /examples/postmark/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/postmark/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['custom'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/postmark/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-with-postmark", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "sideEffects": false, 7 | "main": "./dist/index.js", 8 | "module": "./dist/index.mjs", 9 | "types": "./dist/index.d.ts", 10 | "files": [ 11 | "dist/**" 12 | ], 13 | "scripts": { 14 | "build": "tsup src/index.tsx --format esm,cjs --dts --external react", 15 | "dev": "tsup src/index.tsx --format esm,cjs --dts --external react --watch", 16 | "clean": "rm -rf dist" 17 | }, 18 | "dependencies": { 19 | "@react-email/components": "*", 20 | "postmark": "3.0.14", 21 | "react": "19.0.0-rc.0" 22 | }, 23 | "devDependencies": { 24 | "tsup": "6.2.3", 25 | "typescript": "4.8.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/postmark/src/email.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Button } from "@react-email/components"; 2 | 3 | interface EmailProps { 4 | url: string; 5 | } 6 | 7 | export const Email: React.FC> = ({ url }) => { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /examples/postmark/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/components"; 2 | import postmark from "postmark"; 3 | import { Email } from "./email"; 4 | 5 | // eslint-disable-next-line turbo/no-undeclared-env-vars 6 | const client = new postmark.ServerClient(process.env.POSTMARK_API_KEY || ""); 7 | 8 | const emailHtml = render(); 9 | 10 | const options = { 11 | From: "you@example.com", 12 | To: "user@gmail.com", 13 | Subject: "hello world", 14 | HtmlBody: emailHtml, 15 | }; 16 | 17 | client.sendEmail(options); 18 | -------------------------------------------------------------------------------- /examples/postmark/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "inlineSources": false, 9 | "isolatedModules": true, 10 | "moduleResolution": "node", 11 | "noUnusedLocals": false, 12 | "noUnusedParameters": false, 13 | "preserveWatchOutput": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "strictNullChecks": true, 17 | "jsx": "react-jsx", 18 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 19 | "module": "ESNext", 20 | "target": "es6", 21 | "types": ["vitest/globals"] 22 | }, 23 | "include": ["."], 24 | "exclude": ["dist", "build", "node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /examples/resend/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /examples/resend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-with-resend", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "sideEffects": false, 7 | "scripts": { 8 | "build": "next build", 9 | "dev": "next dev", 10 | "start": "next start" 11 | }, 12 | "dependencies": { 13 | "next": "13.5.6", 14 | "react": "19.0.0-rc.0", 15 | "react-dom": "19.0.0-rc.0", 16 | "resend": "^3.2.0" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^20.2.5", 20 | "@types/react": "npm:types-react@rc", 21 | "@types/react-dom": "npm:types-react-dom@rc", 22 | "typescript": "^5.1.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/resend/src/lib/resend.ts: -------------------------------------------------------------------------------- 1 | import { Resend } from "resend"; 2 | 3 | export const resend = new Resend(process.env.RESEND_API_KEY!); 4 | -------------------------------------------------------------------------------- /examples/resend/src/pages/api/send.ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from "next"; 2 | import { WaitlistEmail } from "../../../transactional/emails/waitlist"; 3 | import { resend } from "../../lib/resend"; 4 | 5 | const send = async (req: NextApiRequest, res: NextApiResponse) => { 6 | const { method } = req; 7 | 8 | switch (method) { 9 | case "GET": { 10 | const data = await resend.emails.send({ 11 | from: "bu@resend.dev", 12 | to: "delivered@resend.dev", 13 | subject: "Waitlist", 14 | react: WaitlistEmail({ name: "Bu" }), 15 | }); 16 | 17 | return res.status(200).send(data); 18 | } 19 | default: 20 | res.setHeader("Allow", ["GET"]); 21 | res.status(405).end(`Method ${method} Not Allowed`); 22 | } 23 | }; 24 | 25 | export default send; 26 | -------------------------------------------------------------------------------- /examples/resend/transactional/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emails", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "email dev", 7 | "export": "email export" 8 | }, 9 | "dependencies": { 10 | "@react-email/components": "*", 11 | "react-email": "2.1.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/resend/transactional/readme.md: -------------------------------------------------------------------------------- 1 | # React Email Starter 2 | 3 | A live preview right in your browser so you don't need to keep sending real emails during development. 4 | 5 | ## Getting Started 6 | 7 | First, install the dependencies: 8 | 9 | ```sh 10 | npm install 11 | # or 12 | yarn 13 | ``` 14 | 15 | Then, run the development server: 16 | 17 | ```sh 18 | npm run dev 19 | # or 20 | yarn dev 21 | ``` 22 | 23 | Open [localhost:3000](http://localhost:3000) with your browser to see the result. 24 | 25 | ## License 26 | 27 | MIT License 28 | -------------------------------------------------------------------------------- /examples/resend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "dom", 5 | "dom.iterable", 6 | "esnext" 7 | ], 8 | "allowJs": true, 9 | "skipLibCheck": true, 10 | "strict": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "noEmit": true, 13 | "incremental": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve" 20 | }, 21 | "include": [ 22 | "next-env.d.ts", 23 | "**/*.ts", 24 | "**/*.tsx" 25 | ], 26 | "exclude": [ 27 | "node_modules" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /examples/scaleway/next/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /examples/scaleway/next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-with-scaleway", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "sideEffects": false, 7 | "scripts": { 8 | "build": "next build", 9 | "dev": "next dev", 10 | "start": "next start" 11 | }, 12 | "dependencies": { 13 | "@react-email/render": "*", 14 | "@scaleway/sdk": "1.5.0", 15 | "next": "13.5.6", 16 | "react": "19.0.0-rc.0", 17 | "react-dom": "19.0.0-rc.0" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "18.14.6", 21 | "@types/react": "npm:types-react@rc", 22 | "@types/react-dom": "npm:types-react-dom@rc", 23 | "typescript": "4.9.5" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/scaleway/next/src/lib/scaleway.ts: -------------------------------------------------------------------------------- 1 | import { createClient, TransactionalEmail } from "@scaleway/sdk"; 2 | 3 | const client = createClient({ 4 | accessKey: process.env.ACCESS_KEY, 5 | secretKey: process.env.SECRET_KEY, 6 | defaultProjectId: process.env.PROJECT_ID, 7 | defaultRegion: "fr-par", 8 | defaultZone: "fr-par-1", 9 | }); 10 | 11 | export const scalewayTEM = new TransactionalEmail.v1alpha1.API(client); 12 | -------------------------------------------------------------------------------- /examples/scaleway/next/src/pages/api/send.ts: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/render"; 2 | import type { NextApiRequest, NextApiResponse } from "next"; 3 | import { WaitlistEmail } from "../../../transactional/emails/waitlist"; 4 | import { scalewayTEM } from "../../lib/scaleway"; 5 | 6 | const send = async (req: NextApiRequest, res: NextApiResponse) => { 7 | if (req.method !== "POST") { 8 | res.setHeader("Allow", ["POST"]); 9 | res.status(405).end(`Method ${req.method} Not Allowed`); 10 | return; 11 | } 12 | 13 | await scalewayTEM.createEmail({ 14 | from: { 15 | email: "you@example.com", 16 | name: "You", 17 | }, 18 | to: [ 19 | { 20 | email: "user@gmail.com", 21 | name: "User", 22 | }, 23 | ], 24 | subject: "Waitlist", 25 | html: render(WaitlistEmail({ name: "User" })), 26 | text: "", 27 | }); 28 | 29 | return res.status(200).send({ data: "Email sent successfully" }); 30 | }; 31 | 32 | export default send; 33 | -------------------------------------------------------------------------------- /examples/scaleway/next/transactional/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emails", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "email dev", 7 | "export": "email export" 8 | }, 9 | "dependencies": { 10 | "@react-email/components": "*", 11 | "react-email": "2.1.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/scaleway/next/transactional/readme.md: -------------------------------------------------------------------------------- 1 | # React Email Starter 2 | 3 | A live preview right in your browser so you don't need to keep sending real emails during development. 4 | 5 | ## Getting Started 6 | 7 | First, install the dependencies: 8 | 9 | ```sh 10 | npm install 11 | # or 12 | yarn 13 | ``` 14 | 15 | Then, run the development server: 16 | 17 | ```sh 18 | npm run dev 19 | # or 20 | yarn dev 21 | ``` 22 | 23 | Open [localhost:3000](http://localhost:3000) with your browser to see the result. 24 | 25 | ## License 26 | 27 | MIT License 28 | -------------------------------------------------------------------------------- /examples/scaleway/next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "dom", 5 | "dom.iterable", 6 | "esnext" 7 | ], 8 | "allowJs": true, 9 | "skipLibCheck": true, 10 | "strict": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "noEmit": true, 13 | "incremental": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve" 20 | }, 21 | "include": [ 22 | "next-env.d.ts", 23 | "**/*.ts", 24 | "**/*.tsx" 25 | ], 26 | "exclude": [ 27 | "node_modules" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /examples/scaleway/node/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [[ 3 | "@babel/preset-react", 4 | { 5 | "runtime": "automatic" 6 | }] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /examples/scaleway/node/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['custom'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/scaleway/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-with-scaleway", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "sideEffects": false, 7 | "main": "./dist/index.js", 8 | "module": "./dist/index.mjs", 9 | "types": "./dist/index.d.ts", 10 | "type": "module", 11 | "files": [ 12 | "dist/**" 13 | ], 14 | "scripts": { 15 | "build": "tsup src/index.tsx --format cjs --dts --external react --env.NODE_ENV production ", 16 | "build:env": "npx dotenv-cli dotenv -e .env tsup src/index.tsx --format cjs --dts --external react --env.NODE_ENV production ", 17 | "dev": "tsup src/index.tsx --format cjs --dts --external react --watch --env.NODE_ENV developpement" 18 | }, 19 | "dependencies": { 20 | "@scaleway/sdk": "1.4.0", 21 | "@react-email/components": "*", 22 | "react": "19.0.0-rc.0" 23 | }, 24 | "devDependencies": { 25 | "tsup": "6.2.3", 26 | "typescript": "4.8.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/scaleway/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "inlineSources": false, 9 | "isolatedModules": true, 10 | "moduleResolution": "node", 11 | "noUnusedLocals": false, 12 | "noUnusedParameters": false, 13 | "preserveWatchOutput": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "strictNullChecks": true, 17 | "jsx": "react-jsx", 18 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 19 | "module": "ESNext", 20 | "target": "es6", 21 | "types": ["vitest/globals"] 22 | }, 23 | "include": ["."], 24 | "exclude": ["dist", "build", "node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /examples/sendgrid/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/sendgrid/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['custom'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/sendgrid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-with-sendgrid", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "sideEffects": false, 7 | "main": "./dist/index.js", 8 | "module": "./dist/index.mjs", 9 | "types": "./dist/index.d.ts", 10 | "files": [ 11 | "dist/**" 12 | ], 13 | "scripts": { 14 | "build": "tsup src/index.tsx --format esm,cjs --dts --external react", 15 | "dev": "tsup src/index.tsx --format esm,cjs --dts --external react --watch", 16 | "clean": "rm -rf dist" 17 | }, 18 | "dependencies": { 19 | "@sendgrid/mail": "7.7.0", 20 | "@react-email/components": "*", 21 | "react": "19.0.0-rc.0" 22 | }, 23 | "devDependencies": { 24 | "tsup": "6.2.3", 25 | "typescript": "4.8.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/sendgrid/src/email.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Button } from "@react-email/components"; 2 | 3 | interface EmailProps { 4 | url: string; 5 | } 6 | 7 | export const Email: React.FC> = ({ url }) => { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /examples/sendgrid/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/components"; 2 | import sendgrid from "@sendgrid/mail"; 3 | import { Email } from "./email"; 4 | 5 | // eslint-disable-next-line turbo/no-undeclared-env-vars 6 | sendgrid.setApiKey(process.env.SENDGRID_API_KEY || ""); 7 | 8 | const emailHtml = render(); 9 | 10 | const options = { 11 | from: "you@example.com", 12 | to: "user@gmail.com", 13 | subject: "hello world", 14 | html: emailHtml, 15 | }; 16 | 17 | sendgrid.send(options); 18 | -------------------------------------------------------------------------------- /examples/sendgrid/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": false, 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "inlineSources": false, 9 | "isolatedModules": true, 10 | "moduleResolution": "node", 11 | "noUnusedLocals": false, 12 | "noUnusedParameters": false, 13 | "preserveWatchOutput": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "strictNullChecks": true, 17 | "jsx": "react-jsx", 18 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 19 | "module": "ESNext", 20 | "target": "es6", 21 | "types": ["vitest/globals"] 22 | }, 23 | "include": ["."], 24 | "exclude": ["dist", "build", "node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/body/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/body/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/body/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/body 2 | 3 | ## 0.0.10-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.9 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.9-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/body/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/body/src/body.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type BodyElement = React.ElementRef<"body">; 4 | type RootProps = React.ComponentPropsWithoutRef<"body">; 5 | 6 | export type BodyProps = RootProps; 7 | 8 | export const Body = React.forwardRef>( 9 | ({ children, style, ...props }, ref) => { 10 | return ( 11 | 12 | {children} 13 | 14 | ); 15 | }, 16 | ); 17 | 18 | Body.displayName = "Body"; 19 | -------------------------------------------------------------------------------- /packages/body/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./body"; 2 | -------------------------------------------------------------------------------- /packages/body/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/button/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/button/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/button/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/button 2 | 3 | ## 0.0.17-canary.1 4 | 5 | ### Patch Changes 6 | 7 | - 8538cb3: Add missing `msoPaddingAlt` to containing `
` tag 8 | 9 | ## 0.0.17-canary.0 10 | 11 | ### Patch Changes 12 | 13 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 14 | 15 | ## 0.0.16 16 | 17 | ### Patch changes 18 | 19 | - Fixes horizontal padding not working on Outlook for Windows 20 | - Add forward ref 21 | 22 | ## 0.0.16-canary.1 23 | 24 | ### Patch changes 25 | 26 | - Fixes horizontal padding not working on Outlook for Windows 27 | 28 | ## 0.0.16-canary.0 29 | 30 | ### Patch changes 31 | 32 | - Add forward ref 33 | -------------------------------------------------------------------------------- /packages/button/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/button/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./button"; 2 | -------------------------------------------------------------------------------- /packages/button/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./px-to-pt"; 2 | export * from "./parse-padding"; 3 | -------------------------------------------------------------------------------- /packages/button/src/utils/px-to-pt.ts: -------------------------------------------------------------------------------- 1 | export const pxToPt = (px: number): number | null => 2 | typeof px === "number" && !isNaN(Number(px)) ? (px * 3) / 4 : null; 3 | -------------------------------------------------------------------------------- /packages/button/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/code-block/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/code-block/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/code-block/.prettierignore: -------------------------------------------------------------------------------- 1 | src/prism.ts -------------------------------------------------------------------------------- /packages/code-block/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/code-block 2 | 3 | ## 0.0.7-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.6 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.6-canary.0 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/code-block/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/code-block/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./code-block"; 2 | export * from "./themes"; 3 | export * from "./languages-available"; 4 | -------------------------------------------------------------------------------- /packages/code-block/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/code-inline/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/code-inline/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/code-inline/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/code-inline 2 | 3 | ## 0.0.4-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.3 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.3-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/code-inline/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/code-inline/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./code-inline"; 2 | -------------------------------------------------------------------------------- /packages/code-inline/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/column/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/column/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/column/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/column 2 | 3 | ## 0.0.12-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.11 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.11-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/column/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/column/src/column.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"td">; 4 | type TdElement = React.ElementRef<"td">; 5 | 6 | export type ColumnProps = RootProps; 7 | 8 | export const Column = React.forwardRef>( 9 | ({ children, style, ...props }, ref) => { 10 | return ( 11 | 12 | {children} 13 | 14 | ); 15 | }, 16 | ); 17 | 18 | Column.displayName = "Column"; 19 | -------------------------------------------------------------------------------- /packages/column/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./column"; 2 | -------------------------------------------------------------------------------- /packages/column/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/components/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/components/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/components/src/__snapshots__/heading.spec.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`render renders the component 1`] = `"

Lorem ipsum

"`; 4 | -------------------------------------------------------------------------------- /packages/components/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "@react-email/body"; 2 | export * from "@react-email/button"; 3 | export * from "@react-email/code-block"; 4 | export * from "@react-email/code-inline"; 5 | export * from "@react-email/column"; 6 | export * from "@react-email/container"; 7 | export * from "@react-email/font"; 8 | export * from "@react-email/head"; 9 | export * from "@react-email/heading"; 10 | export * from "@react-email/hr"; 11 | export * from "@react-email/html"; 12 | export * from "@react-email/img"; 13 | export * from "@react-email/link"; 14 | export * from "@react-email/markdown"; 15 | export * from "@react-email/preview"; 16 | export * from "@react-email/render"; 17 | export * from "@react-email/row"; 18 | export * from "@react-email/section"; 19 | export * from "@react-email/tailwind"; 20 | export * from "@react-email/text"; 21 | -------------------------------------------------------------------------------- /packages/components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/container/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/container/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/container/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/container 2 | 3 | ## 0.0.14-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.13 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.13-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/container/src/container.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"table">; 4 | type TableElement = React.ElementRef<"table">; 5 | 6 | export type ContainerProps = RootProps; 7 | 8 | export const Container = React.forwardRef< 9 | TableElement, 10 | Readonly 11 | >(({ children, style, ...props }, ref) => { 12 | return ( 13 | 24 | 25 | 26 | 27 | 28 | 29 |
{children}
30 | ); 31 | }); 32 | 33 | Container.displayName = "Container"; 34 | -------------------------------------------------------------------------------- /packages/container/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./container"; 2 | -------------------------------------------------------------------------------- /packages/container/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/create-email/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/create-email/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/create-email/.npmignore: -------------------------------------------------------------------------------- 1 | template/node_modules 2 | template/CHANGELOG.md 3 | template/.turbo 4 | -------------------------------------------------------------------------------- /packages/create-email/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # create-email 2 | 3 | ## 0.0.31-canary.4 4 | 5 | ## 0.0.31-canary.3 6 | 7 | ## 0.0.31-canary.2 8 | 9 | ## 0.0.31-canary.1 10 | 11 | ## 0.0.31-canary.0 12 | 13 | ### Patch Changes 14 | 15 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 16 | 17 | ## 0.0.30 18 | 19 | ### Patch Changes 20 | 21 | - 7d9e0c9: Fix error because of node_modules filter 22 | - 4c4bbb6: change internal things related to how the template is versioned 23 | 24 | ## 0.0.30-canary.2 25 | 26 | ### Patch Changes 27 | 28 | - 4f65312: Fix error because of node_modules filter 29 | 30 | ## 0.0.30-canary.1 31 | 32 | ### Patch Changes 33 | 34 | - 525d945: change internal things related to how the template is versioned 35 | -------------------------------------------------------------------------------- /packages/create-email/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-email", 3 | "version": "0.0.31-canary.4", 4 | "description": "The easiest way to get started with React Email", 5 | "main": "src/index.js", 6 | "type": "module", 7 | "license": "MIT", 8 | "dependencies": { 9 | "commander": "9.4.1", 10 | "fs-extra": "11.1.1", 11 | "log-symbols": "5.1.0", 12 | "ora": "6.1.2" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/resend/react-email.git", 17 | "directory": "packages/create-email" 18 | }, 19 | "keywords": [ 20 | "react", 21 | "email" 22 | ], 23 | "engines": { 24 | "node": ">=18.0.0" 25 | }, 26 | "bin": { 27 | "create-email": "src/index.js" 28 | }, 29 | "devDependencies": { 30 | "@babel/preset-react": "7.23.3", 31 | "eslint-config-custom": "workspace:*", 32 | "prettier": "3.0.0", 33 | "tsconfig": "workspace:*" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/create-email/readme.md: -------------------------------------------------------------------------------- 1 | ![create-email cover](https://react.email/static/covers/create-email.png) 2 | 3 |
create-email
4 |
The easiest way to get started with React Email.
5 |
6 |
7 | Website 8 | · 9 | GitHub 10 | · 11 | Discord 12 |
13 | 14 | ## Getting started 15 | 16 | To get started, open a new shell and run: 17 | 18 | ```sh 19 | npx create-email 20 | ``` 21 | 22 | This will create a new folder called `emails` with a few email templates. 23 | 24 | ## Options 25 | 26 | Alternatively, you can pass a parameter to specify the name of the folder: 27 | 28 | ```sh 29 | npx create-email foo 30 | ``` 31 | 32 | ## License 33 | 34 | MIT License 35 | -------------------------------------------------------------------------------- /packages/create-email/template/.gitignore: -------------------------------------------------------------------------------- 1 | .react-email -------------------------------------------------------------------------------- /packages/create-email/template/emails/static/notion-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/create-email/template/emails/static/notion-logo.png -------------------------------------------------------------------------------- /packages/create-email/template/emails/static/plaid-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/create-email/template/emails/static/plaid-logo.png -------------------------------------------------------------------------------- /packages/create-email/template/emails/static/plaid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/create-email/template/emails/static/plaid.png -------------------------------------------------------------------------------- /packages/create-email/template/emails/static/stripe-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/create-email/template/emails/static/stripe-logo.png -------------------------------------------------------------------------------- /packages/create-email/template/emails/static/vercel-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/create-email/template/emails/static/vercel-arrow.png -------------------------------------------------------------------------------- /packages/create-email/template/emails/static/vercel-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/create-email/template/emails/static/vercel-logo.png -------------------------------------------------------------------------------- /packages/create-email/template/emails/static/vercel-team.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/create-email/template/emails/static/vercel-team.png -------------------------------------------------------------------------------- /packages/create-email/template/emails/static/vercel-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/create-email/template/emails/static/vercel-user.png -------------------------------------------------------------------------------- /packages/create-email/template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-email-starter", 3 | "version": "0.0.31-canary.4", 4 | "private": true, 5 | "scripts": { 6 | "build": "email build", 7 | "dev": "email dev", 8 | "export": "email export" 9 | }, 10 | "dependencies": { 11 | "@react-email/components": "workspace:0.0.23-canary.2", 12 | "react-email": "workspace:2.1.7-canary.2", 13 | "react-dom": "19.0.0-rc.0", 14 | "react": "19.0.0-rc.0" 15 | }, 16 | "devDependencies": { 17 | "@types/react": "npm:types-react@rc", 18 | "@types/react-dom": "npm:types-react-dom@rc" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/create-email/template/readme.md: -------------------------------------------------------------------------------- 1 | # React Email Starter 2 | 3 | A live preview right in your browser so you don't need to keep sending real emails during development. 4 | 5 | ## Getting Started 6 | 7 | First, install the dependencies: 8 | 9 | ```sh 10 | npm install 11 | # or 12 | yarn 13 | ``` 14 | 15 | Then, run the development server: 16 | 17 | ```sh 18 | npm run dev 19 | # or 20 | yarn dev 21 | ``` 22 | 23 | Open [localhost:3000](http://localhost:3000) with your browser to see the result. 24 | 25 | ## License 26 | 27 | MIT License 28 | -------------------------------------------------------------------------------- /packages/create-email/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/README.md: -------------------------------------------------------------------------------- 1 | # `@turbo/eslint-config` 2 | 3 | Collection of internal eslint configurations. 4 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/library.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /* 6 | * This is a custom ESLint configuration for use with 7 | * typescript packages. 8 | * 9 | * This config extends the Vercel Engineering Style Guide. 10 | * For more information, see https://github.com/vercel/style-guide 11 | * 12 | */ 13 | 14 | module.exports = { 15 | extends: [ 16 | "@vercel/style-guide/eslint/node", 17 | "@vercel/style-guide/eslint/typescript", 18 | ] 19 | .map(require.resolve) 20 | .concat(["eslint-config-prettier"]), 21 | parserOptions: { 22 | project, 23 | }, 24 | globals: { 25 | React: true, 26 | JSX: true, 27 | }, 28 | settings: { 29 | "import/resolver": { 30 | typescript: { 31 | project, 32 | }, 33 | }, 34 | }, 35 | rules: { "@typescript-eslint/explicit-function-return-type": "off" }, 36 | ignorePatterns: ["node_modules/", "dist/"], 37 | }; 38 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-custom", 3 | "license": "MIT", 4 | "version": "0.0.0", 5 | "private": true, 6 | "devDependencies": { 7 | "@vercel/style-guide": "5.1.0", 8 | "eslint-config-prettier": "9.0.0", 9 | "eslint-config-turbo": "1.10.12", 10 | "typescript": "5.1.6" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/font/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/font/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/font/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/font 2 | 3 | ## 0.0.8-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.7 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.7-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/font/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/font/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./font"; 2 | -------------------------------------------------------------------------------- /packages/font/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/head/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/head/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/head/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/head 2 | 3 | ## 0.0.11-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.10 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.10-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/head/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/head/src/head.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"head">; 4 | type HeadElement = React.ElementRef<"head">; 5 | 6 | export type HeadProps = RootProps; 7 | 8 | export const Head = React.forwardRef>( 9 | ({ children, ...props }, ref) => ( 10 | 11 | 12 | 13 | {children} 14 | 15 | ), 16 | ); 17 | 18 | Head.displayName = "Head"; 19 | -------------------------------------------------------------------------------- /packages/head/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./head"; 2 | -------------------------------------------------------------------------------- /packages/head/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/heading/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/heading/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/heading/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/heading 2 | 3 | ## 0.0.14-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.13 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.13-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/heading/src/heading.tsx: -------------------------------------------------------------------------------- 1 | import { Slot } from "@radix-ui/react-slot"; 2 | import * as React from "react"; 3 | import type { As, Margin } from "./utils"; 4 | import { withMargin } from "./utils"; 5 | 6 | export type HeadingAs = As<"h1", "h2", "h3", "h4", "h5", "h6">; 7 | export type HeadingProps = HeadingAs & Margin; 8 | 9 | export const Heading: React.FC> = ({ 10 | as: Tag = "h1", 11 | children, 12 | style, 13 | m, 14 | mx, 15 | my, 16 | mt, 17 | mr, 18 | mb, 19 | ml, 20 | ...props 21 | }) => { 22 | return ( 23 | 27 | {children} 28 | 29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /packages/heading/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./heading"; 2 | -------------------------------------------------------------------------------- /packages/heading/src/utils/as.ts: -------------------------------------------------------------------------------- 1 | export type As< 2 | DefaultTag extends React.ElementType, 3 | T1 extends React.ElementType, 4 | T2 extends React.ElementType = T1, 5 | T3 extends React.ElementType = T1, 6 | T4 extends React.ElementType = T1, 7 | T5 extends React.ElementType = T1, 8 | > = 9 | | (React.ComponentPropsWithRef & { 10 | as?: DefaultTag; 11 | }) 12 | | (React.ComponentPropsWithRef & { 13 | as: T1; 14 | }) 15 | | (React.ComponentPropsWithRef & { 16 | as: T2; 17 | }) 18 | | (React.ComponentPropsWithRef & { 19 | as: T3; 20 | }) 21 | | (React.ComponentPropsWithRef & { 22 | as: T4; 23 | }) 24 | | (React.ComponentPropsWithRef & { 25 | as: T5; 26 | }); 27 | -------------------------------------------------------------------------------- /packages/heading/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./as"; 2 | export * from "./spaces"; 3 | -------------------------------------------------------------------------------- /packages/heading/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/hr/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/hr/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/hr/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/hr 2 | 3 | ## 0.0.10-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.9 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.9-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/hr/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/hr/src/hr.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/render"; 2 | import { Hr } from "./index"; 3 | 4 | describe("
component", () => { 5 | it("passes styles and other props correctly", () => { 6 | const style = { 7 | width: "50%", 8 | borderColor: "black", 9 | }; 10 | const html = render(
); 11 | expect(html).toContain("width:50%"); 12 | expect(html).toContain("border-color:black"); 13 | expect(html).toContain('data-testid="hr-test"'); 14 | }); 15 | 16 | it("renders correctly", () => { 17 | const actualOutput = render(
); 18 | expect(actualOutput).toMatchInlineSnapshot( 19 | `"
"`, 20 | ); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/hr/src/hr.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"hr">; 4 | 5 | export type HrProps = RootProps; 6 | 7 | export const Hr = React.forwardRef, Readonly>( 8 | ({ style, ...props }, ref) => ( 9 |
19 | ), 20 | ); 21 | 22 | Hr.displayName = "Hr"; 23 | -------------------------------------------------------------------------------- /packages/hr/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./hr"; 2 | -------------------------------------------------------------------------------- /packages/hr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/html/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/html/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/html/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/html 2 | 3 | ## 0.0.10-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.9 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.9-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/html/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/html/src/html.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@react-email/render"; 2 | import { Html } from "./index"; 3 | 4 | describe(" component", () => { 5 | it("renders children correctly", () => { 6 | const testMessage = "Test message"; 7 | const html = render({testMessage}); 8 | expect(html).toContain(testMessage); 9 | }); 10 | 11 | it("passes props correctly", () => { 12 | const html = render(); 13 | expect(html).toContain('lang="fr"'); 14 | expect(html).toContain('dir="rtl"'); 15 | expect(html).toContain('data-testid="html-test"'); 16 | }); 17 | 18 | it("renders correctly", () => { 19 | const actualOutput = render(); 20 | expect(actualOutput).toMatchInlineSnapshot( 21 | '""', 22 | ); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/html/src/html.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"html">; 4 | 5 | export type HtmlProps = RootProps; 6 | 7 | export const Html = React.forwardRef< 8 | React.ElementRef<"html">, 9 | Readonly 10 | >(({ children, lang = "en", dir = "ltr", ...props }, ref) => ( 11 | 12 | {children} 13 | 14 | )); 15 | 16 | Html.displayName = "Html"; 17 | -------------------------------------------------------------------------------- /packages/html/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./html"; 2 | -------------------------------------------------------------------------------- /packages/html/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/img/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/img/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/img/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/img 2 | 3 | ## 0.0.10-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.9 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.9-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/img/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/img/src/img.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"img">; 4 | 5 | export type ImgProps = RootProps; 6 | 7 | export const Img = React.forwardRef< 8 | React.ElementRef<"img">, 9 | Readonly 10 | >(({ alt, src, width, height, style, ...props }, ref) => ( 11 | {alt} 26 | )); 27 | 28 | Img.displayName = "Img"; 29 | -------------------------------------------------------------------------------- /packages/img/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./img"; 2 | -------------------------------------------------------------------------------- /packages/img/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/link/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/link/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/link/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/link 2 | 3 | ## 0.0.10-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.9 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.9-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/link/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/link/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./link"; 2 | -------------------------------------------------------------------------------- /packages/link/src/link.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"a">; 4 | 5 | export type LinkProps = RootProps; 6 | 7 | export const Link = React.forwardRef< 8 | React.ElementRef<"a">, 9 | Readonly 10 | >(({ target = "_blank", style, ...props }, ref) => ( 11 | 21 | {props.children} 22 | 23 | )); 24 | 25 | Link.displayName = "Link"; 26 | -------------------------------------------------------------------------------- /packages/link/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/markdown/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/markdown/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/markdown/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/markdown 2 | 3 | ## 0.0.12-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.11 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.11-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/markdown/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./markdown"; 2 | -------------------------------------------------------------------------------- /packages/markdown/src/markdown.tsx: -------------------------------------------------------------------------------- 1 | import type { StylesType } from "md-to-react-email"; 2 | import { parseMarkdownToJSX } from "md-to-react-email"; 3 | import * as React from "react"; 4 | 5 | export interface MarkdownProps { 6 | children: string; 7 | markdownCustomStyles?: StylesType; 8 | markdownContainerStyles?: React.CSSProperties; 9 | } 10 | 11 | export const Markdown = React.forwardRef< 12 | React.ElementRef<"div">, 13 | Readonly 14 | >( 15 | ( 16 | { children, markdownContainerStyles, markdownCustomStyles, ...props }, 17 | ref, 18 | ) => { 19 | const parsedMarkdown = parseMarkdownToJSX({ 20 | markdown: children, 21 | customStyles: markdownCustomStyles, 22 | }); 23 | 24 | return ( 25 |
32 | ); 33 | }, 34 | ); 35 | 36 | Markdown.displayName = "Markdown"; 37 | -------------------------------------------------------------------------------- /packages/markdown/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/preview/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/preview/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/preview/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/preview 2 | 3 | ## 0.0.11-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.10 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.10-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/preview/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./preview"; 2 | -------------------------------------------------------------------------------- /packages/preview/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/react-email/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | cli 4 | !src/cli 5 | 6 | # for testing 7 | .for-dependency-graph.ts 8 | static 9 | -------------------------------------------------------------------------------- /packages/react-email/.npmignore: -------------------------------------------------------------------------------- 1 | .react-email 2 | emails 3 | .next 4 | static 5 | node_modules 6 | .turbo 7 | src/cli 8 | tsup.config.ts 9 | -------------------------------------------------------------------------------- /packages/react-email/.prettierignore: -------------------------------------------------------------------------------- 1 | .react-email 2 | dist 3 | preview/.next -------------------------------------------------------------------------------- /packages/react-email/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | quoteProps: 'consistent', 3 | singleQuote: true, 4 | trailingComma: 'all', 5 | printWidth: 80, 6 | useTabs: false, 7 | bracketSpacing: true, 8 | }; 9 | -------------------------------------------------------------------------------- /packages/react-email/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # react-email 2 | 3 | ## 2.1.7-canary.2 4 | 5 | ### Patch Changes 6 | 7 | - 349e5d5: Fixes decorators causing dependency tree babel parsing to fail 8 | - 983626d: Fixes root directories being hidden when they are alone at their depth 9 | 10 | ## 2.1.7-canary.1 11 | 12 | ### Patch Changes 13 | 14 | - 6f5204e: Fixes tooltip color being black for specific theming configurations 15 | 16 | ## 2.1.7-canary.0 17 | 18 | ### Patch Changes 19 | 20 | - 27234ec: update socket.io/socket.io-client to 4.7.5 21 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 22 | 23 | ## 2.1.6 24 | 25 | ### Patch changes 26 | 27 | - Fixes live refresh not working with files outside `emails` directory 28 | - Fixes export failing when templates have different suffixes 29 | 30 | ## 2.1.6-canary.0 31 | 32 | ### Patch changes 33 | 34 | - Fixes live refresh not working with files outside `emails` directory 35 | - Fixes export failing when templates have different suffixes 36 | -------------------------------------------------------------------------------- /packages/react-email/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /packages/react-email/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | // this is needed so that the code for building emails works properly 4 | webpack: ( 5 | /** @type {import('webpack').Configuration & { externals: string[] }} */ 6 | config, 7 | { isServer }, 8 | ) => { 9 | if (isServer) { 10 | config.externals.push('esbuild'); 11 | } 12 | 13 | return config; 14 | }, 15 | // Noticed an issue with typescript transpilation when going from Next 14.1.1 to 14.1.2 16 | // and I narrowed that down into this PR https://github.com/vercel/next.js/pull/62005 17 | // 18 | // What is probably happening is that it's noticing the files for the app are somewhere inside of a `node_modules` and automatically opt-outs of SWC's transpilation. 19 | // 20 | // TODO: Open an issue on Nextjs about this. 21 | transpilePackages: ['react-email'] 22 | }; 23 | -------------------------------------------------------------------------------- /packages/react-email/postcss.config.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path'); 2 | 3 | module.exports = { 4 | plugins: { 5 | tailwindcss: { config: path.resolve(__dirname, 'tailwind.config.ts') }, 6 | autoprefixer: {}, 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /packages/react-email/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/react-email/src/app/favicon.ico -------------------------------------------------------------------------------- /packages/react-email/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | 29 | .popup-open iframe { 30 | pointer-events: none; 31 | } 32 | 33 | nav > div > div > .line { 34 | display: none; 35 | } 36 | -------------------------------------------------------------------------------- /packages/react-email/src/app/inter.ts: -------------------------------------------------------------------------------- 1 | import { Inter } from 'next/font/google'; 2 | 3 | export const inter = Inter({ 4 | subsets: ['latin'], 5 | variable: '--font-inter', 6 | display: 'swap', 7 | }); 8 | -------------------------------------------------------------------------------- /packages/react-email/src/app/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavin-chua/react-email/04d8a0cca824552f0f9dbb7b438f60b01e873fff/packages/react-email/src/app/logo.png -------------------------------------------------------------------------------- /packages/react-email/src/cli/commands/.npmignore: -------------------------------------------------------------------------------- 1 | testing 2 | -------------------------------------------------------------------------------- /packages/react-email/src/cli/commands/dev.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import { startDevServer, setupHotreloading } from '../utils'; 3 | 4 | interface Args { 5 | dir: string; 6 | port: string; 7 | } 8 | 9 | export const dev = async ({ dir: emailsDirRelativePath, port }: Args) => { 10 | try { 11 | if (!fs.existsSync(emailsDirRelativePath)) { 12 | throw new Error(`Missing ${emailsDirRelativePath} folder`); 13 | } 14 | 15 | const devServer = await startDevServer( 16 | emailsDirRelativePath, 17 | emailsDirRelativePath, // defaults to ./emails/static for the static files that are served to the preview 18 | parseInt(port), 19 | ); 20 | 21 | await setupHotreloading(devServer, emailsDirRelativePath); 22 | } catch (error) { 23 | console.log(error); 24 | process.exit(1); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /packages/react-email/src/cli/commands/start.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import path from 'node:path'; 3 | import { spawn } from 'node:child_process'; 4 | 5 | export const start = async () => { 6 | try { 7 | const usersProjectLocation = process.cwd(); 8 | const builtPreviewPath = path.resolve( 9 | usersProjectLocation, 10 | './.react-email', 11 | ); 12 | if (!fs.existsSync(builtPreviewPath)) { 13 | throw new Error( 14 | "Could not find `.react-email`, maybe you haven't ran `email build`?", 15 | ); 16 | } 17 | 18 | const nextStart = spawn('npm', ['start'], { 19 | cwd: builtPreviewPath, 20 | shell: true, 21 | }); 22 | 23 | nextStart.stdout.pipe(process.stdout); 24 | 25 | nextStart.stderr.pipe(process.stderr); 26 | } catch (error) { 27 | console.log(error); 28 | process.exit(1); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /packages/react-email/src/cli/commands/testing/.gitignore: -------------------------------------------------------------------------------- 1 | # for the `email export` command 2 | out 3 | -------------------------------------------------------------------------------- /packages/react-email/src/cli/commands/testing/export.spec.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import fs from 'node:fs'; 3 | import { exportTemplates } from '../export'; 4 | 5 | test('email export', async () => { 6 | const pathToEmailsDirectory = path.resolve( 7 | __dirname, 8 | '../../../../../../apps/demo/emails', 9 | ); 10 | const pathToDumpMarkup = path.resolve(__dirname, './out'); 11 | await exportTemplates(pathToDumpMarkup, pathToEmailsDirectory, { 12 | pretty: true, 13 | silent: true, 14 | }); 15 | 16 | expect(fs.existsSync(pathToDumpMarkup)).toBe(true); 17 | expect( 18 | await fs.promises.readFile( 19 | path.resolve(pathToDumpMarkup, './notifications/vercel-invite-user.html'), 20 | 'utf8', 21 | ), 22 | ).toMatchSnapshot(); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/react-email/src/cli/utils/close-ora-on-sigint.ts: -------------------------------------------------------------------------------- 1 | import type { Ora } from 'ora'; 2 | 3 | export const closeOraOnSIGNIT = (spinner: Ora) => { 4 | process.on('SIGINT', () => { 5 | spinner.stop(); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /packages/react-email/src/cli/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tree'; 2 | export * from './preview'; 3 | -------------------------------------------------------------------------------- /packages/react-email/src/cli/utils/preview/get-env-variables-for-preview-app.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | export const getEnvVariablesForPreviewApp = ( 4 | relativePathToEmailsDirectory: string, 5 | cliPackageLocation: string, 6 | cwd: string, 7 | ) => { 8 | return { 9 | NEXT_PUBLIC_EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory, 10 | NEXT_PUBLIC_CLI_PACKAGE_LOCATION: cliPackageLocation, 11 | NEXT_PUBLIC_OS_PATH_SEPARATOR: path.sep, 12 | NEXT_PUBLIC_USER_PROJECT_LOCATION: cwd, 13 | } as const; 14 | }; 15 | -------------------------------------------------------------------------------- /packages/react-email/src/cli/utils/preview/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hot-reloading/setup-hot-reloading'; 2 | export * from './start-dev-server'; 3 | -------------------------------------------------------------------------------- /packages/react-email/src/cli/utils/tree.spec.ts: -------------------------------------------------------------------------------- 1 | import { tree } from './tree'; 2 | 3 | test('tree(__dirname, 2)', async () => { 4 | expect(await tree(__dirname, 2)).toMatchInlineSnapshot(`"utils 5 | ├── preview 6 | │ ├── hot-reloading 7 | │ ├── get-env-variables-for-preview-app.ts 8 | │ ├── index.ts 9 | │ ├── serve-static-file.ts 10 | │ └── start-dev-server.ts 11 | ├── close-ora-on-sigint.ts 12 | ├── index.ts 13 | ├── tree.spec.ts 14 | └── tree.ts"`); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-arrow-down.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { IconElement, IconProps } from './icon-base'; 3 | import { IconBase } from './icon-base'; 4 | 5 | export const IconArrowDown = React.forwardRef>( 6 | ({ ...props }, forwardedRef) => ( 7 | 8 | 12 | 13 | ), 14 | ); 15 | 16 | IconArrowDown.displayName = 'IconArrowDown'; 17 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-base.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export type IconElement = React.ElementRef<'svg'>; 4 | export type RootProps = React.ComponentPropsWithoutRef<'svg'>; 5 | 6 | export interface IconProps extends RootProps { 7 | size?: number; 8 | } 9 | 10 | export const IconBase = React.forwardRef>( 11 | ({ size = 20, ...props }, forwardedRef) => ( 12 | 21 | ), 22 | ); 23 | 24 | IconBase.displayName = 'IconBase'; 25 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { cn } from '../../utils'; 3 | 4 | export type IconButtonProps = React.ComponentPropsWithoutRef<'button'>; 5 | 6 | export const IconButton = React.forwardRef< 7 | HTMLButtonElement, 8 | Readonly 9 | >(({ children, className, ...props }, forwardedRef) => ( 10 | 21 | )); 22 | 23 | IconButton.displayName = 'IconButton'; 24 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-check.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { IconElement, IconProps } from './icon-base'; 3 | import { IconBase } from './icon-base'; 4 | 5 | export const IconCheck = React.forwardRef>( 6 | ({ ...props }, forwardedRef) => ( 7 | 8 | 15 | 16 | ), 17 | ); 18 | 19 | IconCheck.displayName = 'IconCheck'; 20 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-download.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { IconElement, IconProps } from './icon-base'; 3 | import { IconBase } from './icon-base'; 4 | 5 | export const IconDownload = React.forwardRef>( 6 | ({ ...props }, forwardedRef) => ( 7 | 8 | 15 | 16 | ), 17 | ); 18 | 19 | IconDownload.displayName = 'IconDownload'; 20 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-file.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { IconElement, IconProps } from './icon-base'; 3 | import { IconBase } from './icon-base'; 4 | 5 | export const IconFile = React.forwardRef>( 6 | ({ ...props }, forwardedRef) => ( 7 | 8 | 15 | 16 | ), 17 | ); 18 | 19 | IconFile.displayName = 'IconFile'; 20 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-folder.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { IconElement, IconProps } from './icon-base'; 3 | import { IconBase } from './icon-base'; 4 | 5 | export const IconFolder = React.forwardRef>( 6 | ({ ...props }, forwardedRef) => ( 7 | 8 | 14 | 15 | ), 16 | ); 17 | 18 | IconFolder.displayName = 'IconFolder'; 19 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-monitor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { IconElement, IconProps } from './icon-base'; 3 | import { IconBase } from './icon-base'; 4 | 5 | export const IconMonitor = React.forwardRef>( 6 | ({ ...props }, forwardedRef) => ( 7 | 8 | 15 | 16 | ), 17 | ); 18 | 19 | IconMonitor.displayName = 'IconMonitor'; 20 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-phone.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { IconElement, IconProps } from './icon-base'; 3 | import { IconBase } from './icon-base'; 4 | 5 | export const IconPhone = React.forwardRef>( 6 | ({ ...props }, forwardedRef) => ( 7 | 8 | 15 | 22 | 23 | ), 24 | ); 25 | 26 | IconPhone.displayName = 'IconPhone'; 27 | -------------------------------------------------------------------------------- /packages/react-email/src/components/icons/icon-source.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { IconElement, IconProps } from './icon-base'; 3 | import { IconBase } from './icon-base'; 4 | 5 | export const IconSource = React.forwardRef>( 6 | ({ ...props }, forwardedRef) => ( 7 | 8 | 15 | 16 | ), 17 | ); 18 | 19 | IconSource.displayName = 'IconSource'; 20 | -------------------------------------------------------------------------------- /packages/react-email/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | export * from './code'; 3 | export * from './heading'; 4 | export * from './logo'; 5 | export * from './sidebar'; 6 | export * from './text'; 7 | export * from './topbar'; 8 | -------------------------------------------------------------------------------- /packages/react-email/src/components/sidebar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sidebar'; 2 | -------------------------------------------------------------------------------- /packages/react-email/src/components/tooltip.tsx: -------------------------------------------------------------------------------- 1 | import * as TooltipPrimitive from '@radix-ui/react-tooltip'; 2 | import * as React from 'react'; 3 | import { TooltipContent } from './tooltip-content'; 4 | 5 | type RootProps = React.ComponentPropsWithoutRef; 6 | 7 | export type TooltipProps = RootProps; 8 | 9 | export const TooltipRoot: React.FC> = ({ 10 | children, 11 | ...props 12 | }) => {children}; 13 | 14 | export const Tooltip = Object.assign(TooltipRoot, { 15 | Arrow: TooltipPrimitive.TooltipArrow, 16 | Provider: TooltipPrimitive.TooltipProvider, 17 | Content: TooltipContent, 18 | Trigger: TooltipPrimitive.TooltipTrigger, 19 | }); 20 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/cn.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export const cn = (...inputs: ClassValue[]) => { 5 | return twMerge(clsx(inputs)); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const tabTransition = { 2 | type: 'spring', 3 | stiffness: 2000, 4 | damping: 80, 5 | mass: 1, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/copy-text-to-clipboard.ts: -------------------------------------------------------------------------------- 1 | export const copyTextToClipboard = async (text: string) => { 2 | try { 3 | await navigator.clipboard.writeText(text); 4 | } catch { 5 | throw new Error('Not able to copy'); 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/esbuild/escape-string-for-regex.ts: -------------------------------------------------------------------------------- 1 | export function escapeStringForRegex(string: string) { 2 | return string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d'); 3 | } 4 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/get-email-component.spec.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import { getEmailComponent } from './get-email-component'; 3 | 4 | test('getEmailComponent() with a demo email template', async () => { 5 | const result = await getEmailComponent( 6 | path.resolve( 7 | __dirname, 8 | '../../../../apps/demo/emails/notifications/vercel-invite-user.tsx', 9 | ), 10 | ); 11 | 12 | if ('error' in result) { 13 | console.log(result.error); 14 | expect('error' in result).toBe(false); 15 | } else { 16 | expect(result.emailComponent).toBeTruthy(); 17 | expect(result.sourceMapToOriginalFile).toBeTruthy(); 18 | 19 | const emailHtml = await result.renderAsync( 20 | result.createElement( 21 | result.emailComponent, 22 | result.emailComponent.PreviewProps, 23 | ), 24 | ); 25 | expect(emailHtml).toMatchSnapshot(); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types/as'; 2 | export * from './cn'; 3 | export * from './copy-text-to-clipboard'; 4 | export * from './language-map'; 5 | export * from './unreachable'; 6 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/language-map.ts: -------------------------------------------------------------------------------- 1 | const languageMap = { 2 | jsx: 'React', 3 | markup: 'HTML', 4 | markdown: 'Plain Text', 5 | }; 6 | 7 | export default languageMap; 8 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/types/as.ts: -------------------------------------------------------------------------------- 1 | export type As< 2 | DefaultTag extends React.ElementType, 3 | T1 extends React.ElementType, 4 | T2 extends React.ElementType = T1, 5 | T3 extends React.ElementType = T1, 6 | T4 extends React.ElementType = T1, 7 | T5 extends React.ElementType = T1, 8 | > = 9 | | (React.ComponentPropsWithRef & { 10 | as?: DefaultTag; 11 | }) 12 | | (React.ComponentPropsWithRef & { 13 | as: T1; 14 | }) 15 | | (React.ComponentPropsWithRef & { 16 | as: T2; 17 | }) 18 | | (React.ComponentPropsWithRef & { 19 | as: T3; 20 | }) 21 | | (React.ComponentPropsWithRef & { 22 | as: T4; 23 | }) 24 | | (React.ComponentPropsWithRef & { 25 | as: T5; 26 | }); 27 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/types/email-template.ts: -------------------------------------------------------------------------------- 1 | export interface EmailTemplate { 2 | (props: Record | Record): React.ReactNode; 3 | PreviewProps?: Record; 4 | } 5 | 6 | export const isEmailTemplate = (val: unknown): val is EmailTemplate => { 7 | return typeof val === 'function'; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/types/error-object.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An object that mimics the structure of the Error class, 3 | * we just can't use the Error class here because server actions can't 4 | * return classes 5 | */ 6 | export interface ErrorObject { 7 | name: string; 8 | stack: string | undefined; 9 | cause: unknown; 10 | message: string; 11 | } 12 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/types/hot-reload-change.ts: -------------------------------------------------------------------------------- 1 | import type { HotReloadEvent } from './hot-reload-event'; 2 | 3 | export interface HotReloadChange { 4 | filename: string; 5 | event: HotReloadEvent; 6 | } 7 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/types/hot-reload-event.ts: -------------------------------------------------------------------------------- 1 | export type HotReloadEvent = 2 | | 'add' 3 | | 'addDir' 4 | | 'change' 5 | | 'unlink' 6 | | 'unlinkDir'; 7 | -------------------------------------------------------------------------------- /packages/react-email/src/utils/unreachable.ts: -------------------------------------------------------------------------------- 1 | export const unreachable = ( 2 | condition: string | Record, 3 | message = `Entered unreachable code. Received '${ 4 | typeof condition === 'string' ? condition : JSON.stringify(condition) 5 | }'.`, 6 | ): never => { 7 | throw new TypeError(message); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/react-email/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig({ 4 | dts: true, 5 | entry: ['./src/cli/index.ts'], 6 | format: ['esm', 'cjs'], 7 | outDir: 'cli', 8 | }); 9 | -------------------------------------------------------------------------------- /packages/render/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/render/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | rules: { 4 | "import/no-default-export": "off", 5 | "@typescript-eslint/consistent-type-imports": "off", 6 | "tsdoc/syntax": "off" 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /packages/render/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/render 2 | 3 | ## 0.0.18-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | -------------------------------------------------------------------------------- /packages/render/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/render/src/browser/index.ts: -------------------------------------------------------------------------------- 1 | export * from "../shared/render"; 2 | export * from "./render-async"; 3 | 4 | export * from "../shared/options"; 5 | export * from "../shared/plain-text-selectors"; 6 | -------------------------------------------------------------------------------- /packages/render/src/node/index.ts: -------------------------------------------------------------------------------- 1 | export * from "../shared/render"; 2 | export * from "./render-async"; 3 | 4 | export * from "../shared/options"; 5 | export * from "../shared/plain-text-selectors"; 6 | -------------------------------------------------------------------------------- /packages/render/src/shared/options.ts: -------------------------------------------------------------------------------- 1 | import type { HtmlToTextOptions } from "html-to-text"; 2 | 3 | export type Options = { 4 | pretty?: boolean; 5 | } & ( 6 | | { 7 | plainText?: false; 8 | } 9 | | { 10 | plainText?: true; 11 | /** 12 | * These are options you can pass down directly to the library we use for 13 | * converting the rendered email's HTML into plain text. 14 | * 15 | * @see https://github.com/html-to-text/node-html-to-text 16 | */ 17 | htmlToTextOptions?: HtmlToTextOptions; 18 | } 19 | ); 20 | -------------------------------------------------------------------------------- /packages/render/src/shared/plain-text-selectors.ts: -------------------------------------------------------------------------------- 1 | import type { SelectorDefinition } from "html-to-text"; 2 | 3 | export const plainTextSelectors: SelectorDefinition[] = [ 4 | { selector: "img", format: "skip" }, 5 | { selector: "#__react-email-preview", format: "skip" }, 6 | { 7 | selector: "a", 8 | options: { linkBrackets: false }, 9 | }, 10 | ]; 11 | -------------------------------------------------------------------------------- /packages/render/src/shared/react-internals.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-dom/server.browser" { 2 | export * from "react-dom/server"; 3 | } 4 | -------------------------------------------------------------------------------- /packages/render/src/shared/utils/pretty.ts: -------------------------------------------------------------------------------- 1 | // importing the exact function used here will cause 2 | // issues with esm because js-beautify is written with commonjs only 3 | import jsBeautify from "js-beautify"; 4 | 5 | const defaults = { 6 | unformatted: ["code", "pre", "em", "strong", "span"], 7 | indent_inner_html: true, 8 | indent_char: " ", 9 | indent_size: 2, 10 | sep: "\n", 11 | }; 12 | 13 | export const pretty = (str: string, options = {}) => { 14 | return jsBeautify.html(str, { ...defaults, ...options }); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/render/src/shared/utils/preview.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export const Preview: React.FC = () => ( 4 | <> 5 |
This should be hidden from plain text
6 |

This should be rendered in plain text

7 | 8 | ); 9 | -------------------------------------------------------------------------------- /packages/render/src/shared/utils/template.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | interface TemplateProps { 4 | firstName: string; 5 | } 6 | 7 | export const Template: React.FC> = ({ firstName }) => ( 8 | <> 9 |

Welcome, {firstName}!

10 | test 11 |

Thanks for trying our product. We're thrilled to have you on board!

12 | 13 | ); 14 | -------------------------------------------------------------------------------- /packages/render/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/render/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig([ 4 | { 5 | dts: true, 6 | entry: ["./src/node/index.ts"], 7 | outDir: "./dist/node", 8 | format: ["cjs", "esm"], 9 | }, 10 | { 11 | dts: true, 12 | entry: ["./src/browser/index.ts"], 13 | outDir: "./dist/browser", 14 | format: ["cjs", "esm"], 15 | }, 16 | ]); 17 | -------------------------------------------------------------------------------- /packages/row/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } -------------------------------------------------------------------------------- /packages/row/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/row/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/row 2 | 3 | ## 0.0.10-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.9 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.9-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/row/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/row/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./row"; 2 | -------------------------------------------------------------------------------- /packages/row/src/row.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"table">; 4 | 5 | export interface RowProps extends RootProps { 6 | children: React.ReactNode; 7 | } 8 | 9 | export const Row = React.forwardRef< 10 | React.ElementRef<"table">, 11 | Readonly 12 | >(({ children, style, ...props }, ref) => { 13 | return ( 14 | 25 | 26 | {children} 27 | 28 |
29 | ); 30 | }); 31 | 32 | Row.displayName = "Row"; 33 | -------------------------------------------------------------------------------- /packages/row/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/section/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/section/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/section/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/section 2 | 3 | ## 0.0.14-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.13 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.13-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/section/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./section"; 2 | -------------------------------------------------------------------------------- /packages/section/src/section.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"table">; 4 | 5 | export type SectionProps = RootProps; 6 | 7 | export const Section = React.forwardRef< 8 | React.ElementRef<"table">, 9 | Readonly 10 | >(({ children, style, ...props }, ref) => { 11 | return ( 12 | 23 | 24 | 25 | 26 | 27 | 28 |
{children}
29 | ); 30 | }); 31 | 32 | Section.displayName = "Section"; 33 | -------------------------------------------------------------------------------- /packages/section/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/tailwind/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/tailwind/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').ESLint.ConfigData} */ 2 | module.exports = { 3 | extends: ["custom/react-internal"], 4 | plugins: [ 5 | /* just a plugin to create custom linting rules with regex */ 6 | "regex" 7 | ], 8 | rules: { 9 | "regex/invalid": [ 10 | "error", [ 11 | { 12 | "message": "Do not use negative look behinds as they may harm experience for some users (see https://github.com/resend/react-email/issues/549)", 13 | "regex": "\\(\\?, 9 | ) { 10 | return (className: string) => { 11 | const classes = className.split(" "); 12 | 13 | const residualClasses = []; 14 | let styles: React.CSSProperties = {}; 15 | 16 | for (const singleClass of classes) { 17 | if (singleClass in stylePerClass) { 18 | styles = { 19 | ...styles, 20 | ...stylePerClass[singleClass], 21 | }; 22 | } else { 23 | residualClasses.push(singleClass); 24 | } 25 | } 26 | 27 | return { 28 | styles, 29 | residualClassName: residualClasses.join(" "), 30 | }; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /packages/tailwind/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./tailwind"; 2 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/__snapshots__/quick-safe-render-to-string.spec.tsx.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`quick safe render to string 1`] = `"

"`; 4 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/compatibility/escape-class-name.spec.ts: -------------------------------------------------------------------------------- 1 | import { escapeClassName } from "./escape-class-name"; 2 | 3 | describe("escapeClassName function", () => { 4 | it("should escape the first character properly", () => { 5 | expect(escapeClassName("[min-height-")).toBe("\\[min-height-"); 6 | }); 7 | 8 | it("should not escape an already escaped first-character", () => { 9 | expect(escapeClassName("\\[min-height-")).toBe("\\[min-height-"); 10 | }); 11 | 12 | it("should escape `min-height-[calc(25px+100%-20%*2/4)]` correctly", () => { 13 | expect(escapeClassName("min-height-[calc(25px+100%-20%*2/4)]")).toBe( 14 | "min-height-\\[calc\\(25px\\+100\\%-20\\%\\*2\\/4\\)\\]", 15 | ); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/compatibility/escape-class-name.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Escapes all characters that may not be accepted on 3 | * CSS selectors by using the regex "[^a-zA-Z0-9\-_]". 4 | * 5 | * Also does a bit more trickery to avoid escaping already 6 | * escaped characters. 7 | */ 8 | export const escapeClassName = (className: string) => { 9 | return className.replace( 10 | /* we need this look ahead capturing group to avoid using negative look behinds */ 11 | /([^\\]|^)(?=([^a-zA-Z0-9\-_]))/g, 12 | (match, prefixCharacter: string, characterToEscape: string) => { 13 | if (prefixCharacter === "" && characterToEscape === "\\") return match; 14 | 15 | return `${prefixCharacter}\\`; 16 | }, 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/compatibility/make-all-rule-properties-important.ts: -------------------------------------------------------------------------------- 1 | export function makeAllRulePropertiesImportant(ruleContent: string) { 2 | return ruleContent 3 | .split(";") 4 | .map((declaration) => 5 | declaration.endsWith("!important") 6 | ? declaration.trim() 7 | : `${declaration.trim()}!important`, 8 | ) 9 | .join(";"); 10 | } 11 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/compatibility/sanitize-class-name.spec.ts: -------------------------------------------------------------------------------- 1 | import { sanitizeClassName } from "./sanitize-class-name"; 2 | 3 | test("sanitizeClassName", () => { 4 | expect(sanitizeClassName("min-height-[calc(25px+100%-20%*2/4)]")).toBe( 5 | "min-height-calc25pxplus100pc-20pc_2_4", 6 | ); 7 | }); 8 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/compatibility/sanitize-class-name.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Replaces special characters to avoid problems on email clients. 3 | * 4 | * @param className - This should not come with any escaped charcters, it should come the same 5 | * as is on the `className` attribute on React elements. 6 | */ 7 | export const sanitizeClassName = (className: string) => { 8 | return className 9 | .replaceAll("+", "plus") 10 | .replaceAll("[", "") 11 | .replaceAll("%", "pc") 12 | .replaceAll("]", "") 13 | .replaceAll("(", "") 14 | .replaceAll(")", "") 15 | .replaceAll("!", "imprtnt") 16 | .replaceAll(">", "gt") 17 | .replaceAll("<", "lt") 18 | .replaceAll("=", "eq") 19 | .replace(/[^a-zA-Z0-9\-_]/g, "_"); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/compatibility/sanitize-rule-selector.ts: -------------------------------------------------------------------------------- 1 | import { sanitizeClassName } from "./sanitize-class-name"; 2 | import { unescapeClass } from "./unescape-class"; 3 | 4 | export function sanitizeRuleSelector(classSelector: string) { 5 | const unescapedClass = unescapeClass(classSelector); 6 | 7 | return sanitizeClassName(unescapedClass); 8 | } 9 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/compatibility/unescape-class.ts: -------------------------------------------------------------------------------- 1 | export function unescapeClass(singleClass: string) { 2 | return singleClass.replaceAll(/\\[0-9]|\\/g, ""); 3 | } 4 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/compatibility/use-rgb-non-spaced-syntax.spec.ts: -------------------------------------------------------------------------------- 1 | import { useRgbNonSpacedSyntax } from "./use-rgb-non-spaced-syntax"; 2 | 3 | test("useRgbNonSpacedSyntax", () => { 4 | const css = `.bg-red-500{ 5 | background-color: rgb(239 68 68 / 1); 6 | color: rgb(239 68 68 / 0.1) 7 | }`; 8 | expect(useRgbNonSpacedSyntax(css)).toBe(`.bg-red-500{ 9 | background-color: rgb(239,68,68); 10 | color: rgb(239,68,68,0.1) 11 | }`); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/compatibility/use-rgb-non-spaced-syntax.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is to avoid problems on email clients that don't allow for spaced syntax on 3 | * rgb. 4 | * 5 | * See https://www.caniemail.com/features/css-rgb/ 6 | */ 7 | export const useRgbNonSpacedSyntax = (css: string) => { 8 | // Thanks tw-to-css! 9 | // from https://github.com/vinicoder/tw-to-css/blob/main/src/util/format-css.ts 10 | const regex = /rgb\(\s*(\d+)\s*(\d+)\s*(\d+)(?:\s*\/\s*([\d%.]+))?\s*\)/gm; 11 | 12 | return css.replaceAll(regex, (_match, r, g, b, a) => { 13 | const alpha = a === "1" || typeof a === "undefined" ? "" : `,${a}`; 14 | return `rgb(${r},${g},${b}${alpha})`; 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/css/media-queries/separate-media-queries-from-css.ts: -------------------------------------------------------------------------------- 1 | export function separateMediaQueriesFromCSS( 2 | css: string, 3 | ): [cssWithoutMediaQueries: string, mediaQueries: string[]] { 4 | let cssWithoutMediaQueries = css; 5 | const mediaQueries: string[] = []; 6 | 7 | for (const match of css.matchAll( 8 | /@media\s*[^{]*\{(?:[^{}]*\{[^{}]*\})*[^{}]*\}/gm, 9 | )) { 10 | const [mediaQuery] = match; 11 | cssWithoutMediaQueries = cssWithoutMediaQueries.replace(mediaQuery, ""); 12 | 13 | mediaQueries.push(mediaQuery); 14 | } 15 | 16 | return [cssWithoutMediaQueries, mediaQueries]; 17 | } 18 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/css/minify-css.ts: -------------------------------------------------------------------------------- 1 | export const minifyCss = (css: string): string => { 2 | // Thanks tw-to-css! 3 | // from https://github.com/vinicoder/tw-to-css/blob/main/src/util/format-css.ts 4 | return ( 5 | css 6 | // Remove comments 7 | .replace(/\/\*[\s\S]*?\*\//gm, "") 8 | 9 | // Remove extra spaces after semicolons and colons 10 | .replace(/;\s+/gm, ";") 11 | .replace(/:\s+/gm, ":") 12 | 13 | // Remove extra spaces before and after brackets 14 | .replace(/\)\s*{/gm, "){") // Remove spaces before opening curly brace after closing parenthesis 15 | .replace(/\s+\(/gm, "(") // Remove spaces before opening parenthesis 16 | .replace(/{\s+/gm, "{") // Remove spaces after opening curly brace 17 | .replace(/}\s+/gm, "}") // Remove spaces before closing curly brace 18 | .replace(/\s*{/gm, "{") // Remove spaces after opening curly brace 19 | .replace(/;?\s*}/gm, "}") 20 | ); // Remove extra spaces and semicolons before closing curly braces 21 | }; 22 | -------------------------------------------------------------------------------- /packages/tailwind/src/utils/css/rules-for.ts: -------------------------------------------------------------------------------- 1 | export interface Rule { 2 | value: string; 3 | selector: string; 4 | content: string; 5 | } 6 | 7 | export function* rulesFor(cssWithRules: string) { 8 | for (const [fullRule, selector, content] of cssWithRules.matchAll( 9 | /\s*\.([\S]+)\s*{([^}]*)}/gm, 10 | )) { 11 | yield { 12 | value: fullRule, 13 | selector, 14 | content, 15 | } satisfies Rule; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/tailwind/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "tsconfig/react-library.json", 4 | "include": ["."], 5 | "exclude": ["dist", "build", "node_modules"], 6 | "compilerOptions": { 7 | "strict": true, 8 | "noEmit": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/text/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/text/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/text/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @react-email/text 2 | 3 | ## 0.0.10-canary.0 4 | 5 | ### Patch Changes 6 | 7 | - a1c016b: Updated peer dependencies to allow for React 19 release candidated and React 19 itself 8 | 9 | ## 0.0.9 10 | 11 | ### Patch changes 12 | 13 | - Add forward ref 14 | 15 | ## 0.0.9-canary.1 16 | 17 | ### Patch changes 18 | 19 | - Add forward ref 20 | -------------------------------------------------------------------------------- /packages/text/license.md: -------------------------------------------------------------------------------- 1 | Copyright 2024 Plus Five Five, Inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /packages/text/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./text"; 2 | -------------------------------------------------------------------------------- /packages/text/src/text.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | type RootProps = React.ComponentPropsWithoutRef<"p">; 4 | 5 | export type TextProps = RootProps; 6 | 7 | export const Text = React.forwardRef< 8 | React.ElementRef<"p">, 9 | Readonly 10 | >(({ style, ...props }, ref) => ( 11 |

21 | )); 22 | 23 | Text.displayName = "Text"; 24 | -------------------------------------------------------------------------------- /packages/text/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noUnusedLocals": false, 14 | "noUnusedParameters": false, 15 | "preserveWatchOutput": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "strictNullChecks": true 19 | }, 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/tsconfig/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "plugins": [{ "name": "next" }], 7 | "allowJs": true, 8 | "declaration": false, 9 | "declarationMap": false, 10 | "incremental": true, 11 | "jsx": "preserve", 12 | "lib": ["dom", "dom.iterable", "esnext"], 13 | "module": "esnext", 14 | "noEmit": true, 15 | "resolveJsonModule": true, 16 | "strict": false, 17 | "target": "es5" 18 | }, 19 | "include": ["src", "next-env.d.ts"], 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsconfig", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/tsconfig/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx", 7 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 8 | "module": "ESNext", 9 | "target": "es6", 10 | "types": ["vitest/globals"] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /patches/process@0.11.10.patch: -------------------------------------------------------------------------------- 1 | diff --git a/browser.js b/browser.js 2 | index d059362306586e0ed53170099e2e34aa7c756adb..ba698532406973655ebe9cb33adee8546daff1cb 100644 3 | --- a/browser.js 4 | +++ b/browser.js 5 | @@ -157,7 +157,9 @@ process.browser = true; 6 | process.env = {}; 7 | process.argv = []; 8 | process.version = ''; // empty string to avoid regexp issues 9 | -process.versions = {}; 10 | +process.versions = { 11 | + node: '18.18.2' // fake node version 12 | +}; 13 | 14 | function noop() {} 15 | 16 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/web" 3 | - "apps/demo" 4 | - "packages/*" 5 | - "packages/create-email/template" 6 | - "benchmarks/*" 7 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base"], 4 | "schedule": ["before 3am on the first day of the month"] 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/base.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "types": ["vitest/globals"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalDependencies": ["**/.env.*local"], 4 | "pipeline": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "outputs": ["dist/**"] 8 | }, 9 | "web#build": { 10 | "dependsOn": ["^build"], 11 | "env": [ 12 | "RESEND_API_KEY", 13 | "NEXT_PUBLIC_SUPABASE_URL", 14 | "NEXT_PUBLIC_SUPABASE_ANON_KEY" 15 | ], 16 | "outputs": [".next/**", "!.next/cache/**"] 17 | }, 18 | "demo#build": { 19 | "dependsOn": ["^build"], 20 | "outputs": [".react-email/**", "!.react-email/.next/cache/**"] 21 | }, 22 | "react-email#build": { 23 | "dependsOn": ["^build"], 24 | "outputs": ["cli/**"] 25 | }, 26 | "lint": {}, 27 | "//#format": {}, 28 | "//#format:check": {}, 29 | "test": {}, 30 | "test:watch": { 31 | "cache": false 32 | }, 33 | "dev": { 34 | "cache": false, 35 | "persistent": true 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { defineConfig } from "vitest/config"; 4 | 5 | export default defineConfig({ 6 | test: { 7 | globals: true, 8 | environment: "happy-dom", 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /vitest.workspace.ts: -------------------------------------------------------------------------------- 1 | export default ["packages/*"]; 2 | --------------------------------------------------------------------------------