mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-09-11 15:26:19 +03:00
Enable easier email dev setup (#1634)
This commit is contained in:
parent
8e0cd05e65
commit
e3c825fae1
@ -8,3 +8,6 @@ export { initSendGridEmailSender as initEmailSender } from "./providers/sendgrid
|
||||
{=# isMailgunProviderUsed =}
|
||||
export { initMailgunEmailSender as initEmailSender } from "./providers/mailgun.js";
|
||||
{=/ isMailgunProviderUsed =}
|
||||
{=# isDummyProviderUsed =}
|
||||
export { initDummyEmailSender as initEmailSender } from "./providers/dummy.js";
|
||||
{=/ isDummyProviderUsed =}
|
||||
|
@ -1,21 +1,28 @@
|
||||
import { EmailSender } from "../types.js";
|
||||
import { DummyEmailProvider, EmailSender } from "../types.js";
|
||||
import { getDefaultFromField } from "../helpers.js";
|
||||
|
||||
export function initDummyEmailSender(): EmailSender {
|
||||
const yellowColor = "\x1b[33m%s\x1b[0m";
|
||||
|
||||
export function initDummyEmailSender(
|
||||
config?: DummyEmailProvider,
|
||||
): EmailSender {
|
||||
const defaultFromField = getDefaultFromField();
|
||||
return {
|
||||
send: async (email) => {
|
||||
const fromField = email.from || defaultFromField;
|
||||
console.log('Test email (not sent):', {
|
||||
from: {
|
||||
email: fromField.email,
|
||||
name: fromField.name,
|
||||
},
|
||||
to: email.to,
|
||||
subject: email.subject,
|
||||
text: email.text,
|
||||
html: email.html,
|
||||
});
|
||||
|
||||
console.log(yellowColor, '╔═══════════════════════╗');
|
||||
console.log(yellowColor, '║ Dummy email sender ✉️ ║');
|
||||
console.log(yellowColor, '╚═══════════════════════╝');
|
||||
console.log(`From: ${fromField.name} <${fromField.email}>`);
|
||||
console.log(`To: ${email.to}`);
|
||||
console.log(`Subject: ${email.subject}`);
|
||||
console.log(yellowColor, '═════════ Text ═════════');
|
||||
console.log(email.text);
|
||||
console.log(yellowColor, '═════════ HTML ═════════');
|
||||
console.log(email.html);
|
||||
console.log(yellowColor, '════════════════════════');
|
||||
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
{{={= =}=}}
|
||||
export type EmailProvider = SMTPEmailProvider | SendGridProvider | MailgunEmailProvider;
|
||||
export type EmailProvider = SMTPEmailProvider | SendGridProvider | MailgunEmailProvider | DummyEmailProvider;
|
||||
|
||||
export type SMTPEmailProvider = {
|
||||
type: "smtp";
|
||||
@ -20,6 +20,10 @@ export type MailgunEmailProvider = {
|
||||
domain: string;
|
||||
};
|
||||
|
||||
export type DummyEmailProvider = {
|
||||
type: "dummy";
|
||||
}
|
||||
|
||||
export type EmailSender = {
|
||||
send: (email: Email) => Promise<SentMessageInfo>;
|
||||
};
|
||||
|
@ -1,9 +1,6 @@
|
||||
{{={= =}=}}
|
||||
import { initEmailSender } from "./core/index.js";
|
||||
|
||||
import waspServerConfig from '../config.js';
|
||||
import { initDummyEmailSender } from "./core/providers/dummy.js";
|
||||
|
||||
{=# isSmtpProviderUsed =}
|
||||
const emailProvider = {
|
||||
type: "smtp",
|
||||
@ -26,10 +23,10 @@ const emailProvider = {
|
||||
domain: process.env.MAILGUN_DOMAIN,
|
||||
} as const;
|
||||
{=/ isMailgunProviderUsed =}
|
||||
{=# isDummyProviderUsed =}
|
||||
const emailProvider = {
|
||||
type: "dummy",
|
||||
} as const;
|
||||
{=/ isDummyProviderUsed =}
|
||||
|
||||
const areEmailsSentInDevelopment = process.env.SEND_EMAILS_IN_DEVELOPMENT === "true";
|
||||
const isDummyEmailSenderUsed = waspServerConfig.isDevelopment && !areEmailsSentInDevelopment;
|
||||
|
||||
export const emailSender = isDummyEmailSenderUsed
|
||||
? initDummyEmailSender()
|
||||
: initEmailSender(emailProvider);
|
||||
export const emailSender = initEmailSender(emailProvider);
|
||||
|
@ -43,7 +43,6 @@ waspComplexTest/.wasp/out/server/src/dbClient.ts
|
||||
waspComplexTest/.wasp/out/server/src/dbSeed/types.ts
|
||||
waspComplexTest/.wasp/out/server/src/email/core/helpers.ts
|
||||
waspComplexTest/.wasp/out/server/src/email/core/index.ts
|
||||
waspComplexTest/.wasp/out/server/src/email/core/providers/dummy.ts
|
||||
waspComplexTest/.wasp/out/server/src/email/core/providers/sendgrid.ts
|
||||
waspComplexTest/.wasp/out/server/src/email/core/types.ts
|
||||
waspComplexTest/.wasp/out/server/src/email/index.ts
|
||||
|
@ -286,13 +286,6 @@
|
||||
],
|
||||
"d524dd9ef27cd311340060411276df0e8ef22db503473f44281832338b954bb7"
|
||||
],
|
||||
[
|
||||
[
|
||||
"file",
|
||||
"server/src/email/core/providers/dummy.ts"
|
||||
],
|
||||
"e93a7a02f50c8466f3e8e89255b98bebde598b25f9969ec117b16f07691575ae"
|
||||
],
|
||||
[
|
||||
[
|
||||
"file",
|
||||
@ -305,14 +298,14 @@
|
||||
"file",
|
||||
"server/src/email/core/types.ts"
|
||||
],
|
||||
"c343f0d87b65d7563816159a88f410b65d78d897822c0bbcd723ca7752e00a20"
|
||||
"0d7c19707f4e7c498a458015b1065b3f84c31e53ba73807707a05b7293473eb2"
|
||||
],
|
||||
[
|
||||
[
|
||||
"file",
|
||||
"server/src/email/index.ts"
|
||||
],
|
||||
"c4864d5c83b96a61b1ddfaac7b52c0898f5cff04320c166c8f658b017952ee05"
|
||||
"4443efa3da16d8d950bde84acd2ed6d9bc3a5d211ce3138248e3b5bad5079978"
|
||||
],
|
||||
[
|
||||
[
|
||||
|
@ -1,24 +0,0 @@
|
||||
import { EmailSender } from "../types.js";
|
||||
import { getDefaultFromField } from "../helpers.js";
|
||||
|
||||
export function initDummyEmailSender(): EmailSender {
|
||||
const defaultFromField = getDefaultFromField();
|
||||
return {
|
||||
send: async (email) => {
|
||||
const fromField = email.from || defaultFromField;
|
||||
console.log('Test email (not sent):', {
|
||||
from: {
|
||||
email: fromField.email,
|
||||
name: fromField.name,
|
||||
},
|
||||
to: email.to,
|
||||
subject: email.subject,
|
||||
text: email.text,
|
||||
html: email.html,
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
export type EmailProvider = SMTPEmailProvider | SendGridProvider | MailgunEmailProvider;
|
||||
export type EmailProvider = SMTPEmailProvider | SendGridProvider | MailgunEmailProvider | DummyEmailProvider;
|
||||
|
||||
export type SMTPEmailProvider = {
|
||||
type: "smtp";
|
||||
@ -19,6 +19,10 @@ export type MailgunEmailProvider = {
|
||||
domain: string;
|
||||
};
|
||||
|
||||
export type DummyEmailProvider = {
|
||||
type: "dummy";
|
||||
}
|
||||
|
||||
export type EmailSender = {
|
||||
send: (email: Email) => Promise<SentMessageInfo>;
|
||||
};
|
||||
|
@ -1,16 +1,8 @@
|
||||
import { initEmailSender } from "./core/index.js";
|
||||
|
||||
import waspServerConfig from '../config.js';
|
||||
import { initDummyEmailSender } from "./core/providers/dummy.js";
|
||||
|
||||
const emailProvider = {
|
||||
type: "sendgrid",
|
||||
apiKey: process.env.SENDGRID_API_KEY,
|
||||
} as const;
|
||||
|
||||
const areEmailsSentInDevelopment = process.env.SEND_EMAILS_IN_DEVELOPMENT === "true";
|
||||
const isDummyEmailSenderUsed = waspServerConfig.isDevelopment && !areEmailsSentInDevelopment;
|
||||
|
||||
export const emailSender = isDummyEmailSenderUsed
|
||||
? initDummyEmailSender()
|
||||
: initEmailSender(emailProvider);
|
||||
export const emailSender = initEmailSender(emailProvider);
|
||||
|
@ -0,0 +1,17 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Session" (
|
||||
"id" TEXT NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Session_id_key" ON "Session"("id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Session_userId_idx" ON "Session"("userId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "Auth"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -15,7 +15,7 @@ data EmailSender = EmailSender
|
||||
}
|
||||
deriving (Show, Eq, Data)
|
||||
|
||||
data EmailProvider = SMTP | SendGrid | Mailgun
|
||||
data EmailProvider = SMTP | SendGrid | Mailgun | Dummy
|
||||
deriving (Eq, Data, Show)
|
||||
|
||||
data EmailFromField = EmailFromField
|
||||
|
@ -28,6 +28,7 @@ import qualified Wasp.AppSpec.App as App
|
||||
import qualified Wasp.AppSpec.App.Auth as Auth
|
||||
import qualified Wasp.AppSpec.App.Client as Client
|
||||
import qualified Wasp.AppSpec.App.Db as AS.Db
|
||||
import qualified Wasp.AppSpec.App.EmailSender as AS.EmailSender
|
||||
import qualified Wasp.AppSpec.App.Wasp as Wasp
|
||||
import Wasp.AppSpec.Core.Decl (takeDecls)
|
||||
import qualified Wasp.AppSpec.Crud as AS.Crud
|
||||
@ -70,6 +71,7 @@ validateAppSpec spec =
|
||||
validateUserEntity spec,
|
||||
validateOnlyEmailOrUsernameAndPasswordAuthIsUsed spec,
|
||||
validateEmailSenderIsDefinedIfEmailAuthIsUsed spec,
|
||||
validateDummyEmailSenderIsNotUsedInProduction spec,
|
||||
validateDbIsPostgresIfPgBossUsed spec,
|
||||
validateApiRoutesAreUnique spec,
|
||||
validateApiNamespacePathsAreUnique spec,
|
||||
@ -177,14 +179,21 @@ validateEmailSenderIsDefinedIfEmailAuthIsUsed :: AppSpec -> [ValidationError]
|
||||
validateEmailSenderIsDefinedIfEmailAuthIsUsed spec = case App.auth app of
|
||||
Nothing -> []
|
||||
Just auth ->
|
||||
if not $ Auth.isEmailAuthEnabled auth
|
||||
then []
|
||||
else case App.emailSender app of
|
||||
Nothing -> [GenericValidationError "app.emailSender must be specified when using email auth."]
|
||||
Just _ -> []
|
||||
if Auth.isEmailAuthEnabled auth && isNothing (App.emailSender app)
|
||||
then [GenericValidationError "app.emailSender must be specified when using email auth. You can use the Dummy email sender for development purposes."]
|
||||
else []
|
||||
where
|
||||
app = snd $ getApp spec
|
||||
|
||||
validateDummyEmailSenderIsNotUsedInProduction :: AppSpec -> [ValidationError]
|
||||
validateDummyEmailSenderIsNotUsedInProduction spec =
|
||||
if AS.isBuild spec && isDummyEmailSenderUsed
|
||||
then [GenericValidationError "app.emailSender must not be set to Dummy when building for production."]
|
||||
else []
|
||||
where
|
||||
isDummyEmailSenderUsed = (AS.EmailSender.provider <$> App.emailSender app) == Just AS.EmailSender.Dummy
|
||||
app = snd $ getApp spec
|
||||
|
||||
validateApiRoutesAreUnique :: AppSpec -> [ValidationError]
|
||||
validateApiRoutesAreUnique spec =
|
||||
if null groupsOfConflictingRoutes
|
||||
|
@ -2,6 +2,7 @@ module Wasp.Generator.ServerGenerator.EmailSender.Providers
|
||||
( smtp,
|
||||
sendGrid,
|
||||
mailgun,
|
||||
dummy,
|
||||
providersDirInServerSrc,
|
||||
EmailSenderProvider (..),
|
||||
)
|
||||
@ -13,7 +14,7 @@ import qualified Wasp.Generator.ServerGenerator.Common as C
|
||||
import qualified Wasp.SemanticVersion as SV
|
||||
|
||||
data EmailSenderProvider = EmailSenderProvider
|
||||
{ npmDependency :: AS.Dependency.Dependency,
|
||||
{ npmDependency :: Maybe AS.Dependency.Dependency,
|
||||
setupFnFile :: Path' (Rel ProvidersDir) File',
|
||||
-- We have to use explicit boolean keys in templates (e.g. "isSMTPProviderEnabled") so each
|
||||
-- provider provides its own key which we pass to the template.
|
||||
@ -26,7 +27,7 @@ data ProvidersDir
|
||||
smtp :: EmailSenderProvider
|
||||
smtp =
|
||||
EmailSenderProvider
|
||||
{ npmDependency = nodeMailerDependency,
|
||||
{ npmDependency = Just nodeMailerDependency,
|
||||
setupFnFile = [relfile|smtp.ts|],
|
||||
isEnabledKey = "isSmtpProviderUsed"
|
||||
}
|
||||
@ -40,7 +41,7 @@ smtp =
|
||||
sendGrid :: EmailSenderProvider
|
||||
sendGrid =
|
||||
EmailSenderProvider
|
||||
{ npmDependency = sendGridDependency,
|
||||
{ npmDependency = Just sendGridDependency,
|
||||
setupFnFile = [relfile|sendgrid.ts|],
|
||||
isEnabledKey = "isSendGridProviderUsed"
|
||||
}
|
||||
@ -54,7 +55,7 @@ sendGrid =
|
||||
mailgun :: EmailSenderProvider
|
||||
mailgun =
|
||||
EmailSenderProvider
|
||||
{ npmDependency = mailgunDependency,
|
||||
{ npmDependency = Just mailgunDependency,
|
||||
setupFnFile = [relfile|mailgun.ts|],
|
||||
isEnabledKey = "isMailgunProviderUsed"
|
||||
}
|
||||
@ -65,5 +66,13 @@ mailgun =
|
||||
mailgunDependency :: AS.Dependency.Dependency
|
||||
mailgunDependency = AS.Dependency.make ("ts-mailgun", show mailgunVersionRange)
|
||||
|
||||
dummy :: EmailSenderProvider
|
||||
dummy =
|
||||
EmailSenderProvider
|
||||
{ npmDependency = Nothing,
|
||||
setupFnFile = [relfile|dummy.ts|],
|
||||
isEnabledKey = "isDummyProviderUsed"
|
||||
}
|
||||
|
||||
providersDirInServerSrc :: Path' (Rel C.ServerTemplatesSrcDir) (Dir ProvidersDir)
|
||||
providersDirInServerSrc = [reldir|email/core/providers|]
|
||||
|
@ -39,8 +39,7 @@ genCore email =
|
||||
sequence
|
||||
[ genCoreIndex email,
|
||||
genCoreTypes email,
|
||||
genCoreHelpers email,
|
||||
genFileCopy [relfile|email/core/providers/dummy.ts|]
|
||||
genCoreHelpers email
|
||||
]
|
||||
<++> genEmailSenderProviderSetupFn email
|
||||
|
||||
@ -94,7 +93,7 @@ depsRequiredByEmail spec = maybeToList maybeNpmDepedency
|
||||
where
|
||||
maybeProvider :: Maybe Providers.EmailSenderProvider
|
||||
maybeProvider = getEmailSenderProvider <$> (AS.App.emailSender . snd . getApp $ spec)
|
||||
maybeNpmDepedency = Providers.npmDependency <$> maybeProvider
|
||||
maybeNpmDepedency = maybeProvider >>= Providers.npmDependency
|
||||
|
||||
getEmailProvidersJson :: EmailSender -> Aeson.Value
|
||||
getEmailProvidersJson email =
|
||||
@ -109,6 +108,7 @@ getEmailSenderProvider email = case AS.EmailSender.provider email of
|
||||
AS.EmailSender.SMTP -> Providers.smtp
|
||||
AS.EmailSender.SendGrid -> Providers.sendGrid
|
||||
AS.EmailSender.Mailgun -> Providers.mailgun
|
||||
AS.EmailSender.Dummy -> Providers.dummy
|
||||
|
||||
genFileCopy :: Path' (Rel C.ServerTemplatesSrcDir) File' -> Generator FileDraft
|
||||
genFileCopy = return . C.mkSrcTmplFd
|
||||
|
@ -220,6 +220,78 @@ spec_AppSpecValid = do
|
||||
`shouldBe` [ ASV.GenericValidationError
|
||||
"Entity 'User' (referenced by app.auth.userEntity) must have an ID field (specified with the '@id' attribute)"
|
||||
]
|
||||
|
||||
describe "should validate email sender setup." $ do
|
||||
let emailAuthConfig =
|
||||
AS.Auth.EmailAuthConfig
|
||||
{ AS.Auth.fromField =
|
||||
AS.EmailSender.EmailFromField
|
||||
{ AS.EmailSender.email = "dummy@info.com",
|
||||
AS.EmailSender.name = Nothing
|
||||
},
|
||||
AS.Auth.emailVerification =
|
||||
AS.Auth.EmailVerification.EmailVerificationConfig
|
||||
{ AS.Auth.EmailVerification.clientRoute = AS.Core.Ref.Ref basicRouteName,
|
||||
AS.Auth.EmailVerification.getEmailContentFn = Nothing
|
||||
},
|
||||
AS.Auth.passwordReset =
|
||||
AS.Auth.PasswordReset.PasswordResetConfig
|
||||
{ AS.Auth.PasswordReset.clientRoute = AS.Core.Ref.Ref basicRouteName,
|
||||
AS.Auth.PasswordReset.getEmailContentFn = Nothing
|
||||
},
|
||||
AS.Auth.allowUnverifiedLogin = Nothing
|
||||
}
|
||||
|
||||
let makeSpec emailSender isBuild =
|
||||
basicAppSpec
|
||||
{ AS.isBuild = isBuild,
|
||||
AS.decls =
|
||||
[ AS.Decl.makeDecl "TestApp" $
|
||||
basicApp
|
||||
{ AS.App.auth =
|
||||
Just
|
||||
AS.Auth.Auth
|
||||
{ AS.Auth.methods =
|
||||
AS.Auth.AuthMethods {email = Just emailAuthConfig, usernameAndPassword = Nothing, google = Nothing, gitHub = Nothing},
|
||||
AS.Auth.userEntity = AS.Core.Ref.Ref userEntityName,
|
||||
AS.Auth.externalAuthEntity = Nothing,
|
||||
AS.Auth.onAuthFailedRedirectTo = "/",
|
||||
AS.Auth.onAuthSucceededRedirectTo = Nothing,
|
||||
AS.Auth.signup = Nothing
|
||||
},
|
||||
AS.App.emailSender = emailSender
|
||||
},
|
||||
AS.Decl.makeDecl userEntityName $
|
||||
AS.Entity.makeEntity
|
||||
( PslM.Body
|
||||
[ PslM.ElementField $ makeIdField "id" PslM.String
|
||||
]
|
||||
),
|
||||
basicPageDecl,
|
||||
basicRouteDecl
|
||||
]
|
||||
}
|
||||
let mailgunEmailSender =
|
||||
AS.EmailSender.EmailSender
|
||||
{ AS.EmailSender.provider = AS.EmailSender.Mailgun,
|
||||
AS.EmailSender.defaultFrom = Nothing
|
||||
}
|
||||
|
||||
let dummyEmailSender =
|
||||
AS.EmailSender.EmailSender
|
||||
{ AS.EmailSender.provider = AS.EmailSender.Dummy,
|
||||
AS.EmailSender.defaultFrom = Nothing
|
||||
}
|
||||
|
||||
it "returns an error if no email sender is set but email auth is used" $ do
|
||||
ASV.validateAppSpec (makeSpec Nothing False) `shouldBe` [ASV.GenericValidationError "app.emailSender must be specified when using email auth. You can use the Dummy email sender for development purposes."]
|
||||
it "returns no error if email sender is defined while using email auth" $ do
|
||||
ASV.validateAppSpec (makeSpec (Just mailgunEmailSender) False) `shouldBe` []
|
||||
it "returns no error if the Dummy email sender is used in development" $ do
|
||||
ASV.validateAppSpec (makeSpec (Just dummyEmailSender) False) `shouldBe` []
|
||||
it "returns an error if the Dummy email sender is used when building the app" $ do
|
||||
ASV.validateAppSpec (makeSpec (Just dummyEmailSender) True)
|
||||
`shouldBe` [ASV.GenericValidationError "app.emailSender must not be set to Dummy when building for production."]
|
||||
where
|
||||
makeIdField name typ =
|
||||
PslM.Field
|
||||
|
4
web/docs/advanced/email/_dummy-provider-note.md
Normal file
4
web/docs/advanced/email/_dummy-provider-note.md
Normal file
@ -0,0 +1,4 @@
|
||||
:::note Dummy Provider is not for production use
|
||||
|
||||
The `Dummy` provider is not for production use. It is only meant to be used during development. If you try building your app with the `Dummy` provider, the build will fail.
|
||||
:::
|
@ -2,14 +2,13 @@
|
||||
title: Sending Emails
|
||||
---
|
||||
|
||||
import SendingEmailsInDevelopment from '../\_sendingEmailsInDevelopment.md'
|
||||
|
||||
import { Required } from '@site/src/components/Tag'
|
||||
import { ShowForTs, ShowForJs } from '@site/src/components/TsJsHelpers'
|
||||
import DummyProviderNote from './_dummy-provider-note.md'
|
||||
|
||||
# Sending Emails
|
||||
|
||||
With Wasp's email sending feature, you can easily integrate email functionality into your web application.
|
||||
With Wasp's email-sending feature, you can easily integrate email functionality into your web application.
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
@ -48,6 +47,7 @@ app Example {
|
||||
|
||||
Choose from one of the providers:
|
||||
|
||||
- `Dummy` (development only),
|
||||
- `Mailgun`,
|
||||
- `SendGrid`
|
||||
- or the good old `SMTP`.
|
||||
@ -56,11 +56,9 @@ Optionally, define the `defaultFrom` field, so you don't need to provide it when
|
||||
|
||||
## Sending Emails
|
||||
|
||||
<SendingEmailsInDevelopment />
|
||||
|
||||
Before jumping into details about setting up various providers, let's see how easy it is to send emails.
|
||||
|
||||
You import the `emailSender` that is provided by the `@wasp/email` module and call the `send` method on it.
|
||||
You import the `emailSender` that is provided by the `@wasp/email/index.js` module and call the `send` method on it.
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
@ -109,7 +107,42 @@ The `send` method returns an object with the status of the sent email. It varies
|
||||
|
||||
## Providers
|
||||
|
||||
For each provider, you'll need to set up env variables in the `.env.server` file at the root of your project.
|
||||
We'll go over all of the available providers in the next section. For some of them, you'll need to set up some env variables. You can do that in the `.env.server` file.
|
||||
|
||||
### Using the Dummy Provider
|
||||
|
||||
<DummyProviderNote />
|
||||
|
||||
To speed up development, Wasp offers a `Dummy` email sender that `console.log`s the emails in the console. Since it doesn't send emails for real, it doesn't require any setup.
|
||||
|
||||
Set the provider to `Dummy` in your `main.wasp` file.
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
app Example {
|
||||
...
|
||||
emailSender: {
|
||||
provider: Dummy,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts" label="TypeScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
app Example {
|
||||
...
|
||||
emailSender: {
|
||||
provider: Dummy,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Using the SMTP Provider
|
||||
|
||||
@ -285,7 +318,9 @@ The `emailSender` dict has the following fields:
|
||||
|
||||
- `provider: Provider` <Required />
|
||||
|
||||
The provider you want to use. Choose from `SMTP`, `Mailgun` or `SendGrid`.
|
||||
The provider you want to use. Choose from `Dummy`, `SMTP`, `Mailgun` or `SendGrid`.
|
||||
|
||||
<DummyProviderNote />
|
||||
|
||||
- `defaultFrom: dict`
|
||||
|
@ -414,9 +414,9 @@ We imported the generated Auth UI components and used them in our pages. Read mo
|
||||
|
||||
To support e-mail verification and password reset flows, we need an e-mail sender. Luckily, Wasp supports several email providers out of the box.
|
||||
|
||||
We'll use SendGrid in this guide to send our e-mails. You can use any of the supported email providers.
|
||||
We'll use the `Dummy` provider to speed up the setup. It just logs the emails to the console instead of sending them. You can use any of the [supported email providers](../advanced/email#providers).
|
||||
|
||||
To set up SendGrid to send emails, we will add the following to our `main.wasp` file:
|
||||
To set up the `Dummy` provider to send emails, add the following to the `main.wasp` file:
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
@ -426,7 +426,7 @@ app myApp {
|
||||
// ...
|
||||
// 7. Set up the email sender
|
||||
emailSender: {
|
||||
provider: SendGrid,
|
||||
provider: Dummy,
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -438,23 +438,13 @@ app myApp {
|
||||
// ...
|
||||
// 7. Set up the email sender
|
||||
emailSender: {
|
||||
provider: SendGrid,
|
||||
provider: Dummy,
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
... and add the following to our `.env.server` file:
|
||||
|
||||
```c title=".env.server"
|
||||
SENDGRID_API_KEY=<your key>
|
||||
```
|
||||
|
||||
If you are not sure how to get a SendGrid API key, read more [here](../advanced/email#getting-the-api-key).
|
||||
|
||||
Read more about setting up email senders in the [sending emails docs](../advanced/email).
|
||||
|
||||
### Conclusion
|
||||
|
||||
That's it! We have set up email authentication in our app. 🎉
|
||||
|
@ -104,7 +104,7 @@ module.exports = {
|
||||
'advanced/deployment/manually',
|
||||
],
|
||||
},
|
||||
'advanced/email',
|
||||
'advanced/email/email',
|
||||
'advanced/jobs',
|
||||
'advanced/web-sockets',
|
||||
'advanced/apis',
|
||||
|
Loading…
Reference in New Issue
Block a user