1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-09 23:45:21 +02:00

noop if no provider or api key

This commit is contained in:
Tyler Myracle 2024-01-20 14:41:41 -06:00
parent 118b2d037e
commit f712d939a4
9 changed files with 41 additions and 27 deletions

View file

@ -44,11 +44,13 @@ NX_TELLER_ENV=sandbox
# EMAIL # EMAIL
######################################################################## ########################################################################
# We use Postmark for transactional emails. You can sign up for a free account # We currently support Postmark for transactional emails. You can sign up for a free account
# and get a free API key at https://postmarkapp.com # and get a free API key at https://postmarkapp.com
NX_POSTMARK_FROM_ADDRESS=account@example.com NX_EMAIL_FROM_ADDRESS=account@example.com
NX_POSTMARK_REPLY_TO_ADDRESS=support@example.com NX_EMAIL_REPLY_TO_ADDRESS=support@example.com
NX_POSTMARK_API_TOKEN= NX_EMAIL_PROVIDER=
NX_EMAIL_PROVIDER_API_TOKEN=
######################################################################## ########################################################################

View file

@ -37,7 +37,7 @@ And dozens upon dozens of smaller features.
This is the current state of building the app. We're actively working to make this process much more streamlined! This is the current state of building the app. We're actively working to make this process much more streamlined!
*You'll need Docker installed to run the app locally.* _You'll need Docker installed to run the app locally._
[Docker Desktop](https://www.docker.com/products/docker-desktop/) is an easy way to get started. [Docker Desktop](https://www.docker.com/products/docker-desktop/) is an easy way to get started.
First, copy the `.env.example` file to `.env`: First, copy the `.env.example` file to `.env`:
@ -48,7 +48,7 @@ cp .env.example .env
Then, create a new secret using `openssl rand -base64 32` and populate `NEXTAUTH_SECRET` in your `.env` file with it. Then, create a new secret using `openssl rand -base64 32` and populate `NEXTAUTH_SECRET` in your `.env` file with it.
To enable transactional emails, you'll need to create a [Postmark](https://postmarkapp.com/) account and add your API key to your `.env` file (`NX_POSTMARK_API_TOKEN`). You can also set the from and reply-to email addresses (`NX_POSTMARK_FROM_ADDRESS` and `NX_POSTMARK_REPLY_TO_ADDRESS`). If you want to run the app without email, you can set `NX_POSTMARK_API_TOKEN` to a dummy value. To enable transactional emails, you'll need to create a [Postmark](https://postmarkapp.com/) account and add your API key to your `.env` file (`NX_EMAIL_PROVIDER_API_TOKEN`) and set `NX_EMAIL_PROVIDER` to `postmark`. You can also set the from and reply-to email addresses (`NX_EMAIL_FROM_ADDRESS` and `NX_EMAIL_REPLY_TO_ADDRESS`). If you want to run the app without email, you can set `NX_EMAIL_PROVIDER_API_TOKEN` to a dummy value.
Maybe uses [Teller](https://teller.io/) for connecting financial accounts. To get started with Teller, you'll need to create an account. Once you've created an account: Maybe uses [Teller](https://teller.io/) for connecting financial accounts. To get started with Teller, you'll need to create an account. Once you've created an account:

View file

@ -2,14 +2,14 @@ import { ServerClient as PostmarkServerClient } from 'postmark'
import env from '../../env' import env from '../../env'
export function initializeEmailClient() { export function initializeEmailClient() {
switch (process.env.NX_EMAIL_PROVIDER) { switch (env.NX_EMAIL_PROVIDER) {
case 'postmark': case 'postmark':
if (env.NX_EMAIL_PROVIDER_API_TOKEN) { if (env.NX_EMAIL_PROVIDER_API_TOKEN) {
return new PostmarkServerClient(env.NX_EMAIL_PROVIDER_API_TOKEN) return new PostmarkServerClient(env.NX_EMAIL_PROVIDER_API_TOKEN)
} else { } else {
throw new Error('Missing Postmark API token') return undefined
} }
default: default:
throw new Error('Invalid email provider') return undefined
} }
} }

View file

@ -259,7 +259,7 @@ router.get(
}) })
) )
// TODO: Implement verification email using Postmark instead of Auth0 // TODO: Implement verification email using internal email service instead of Auth0
router.post( router.post(
'/resend-verification-email', '/resend-verification-email',
endpoint.create({ endpoint.create({

View file

@ -68,6 +68,7 @@ const envSchema = z.object({
NX_EMAIL_FROM_ADDRESS: z.string().default('account@maybe.co'), NX_EMAIL_FROM_ADDRESS: z.string().default('account@maybe.co'),
NX_EMAIL_REPLY_TO_ADDRESS: z.string().default('support@maybe.co'), NX_EMAIL_REPLY_TO_ADDRESS: z.string().default('support@maybe.co'),
NX_EMAIL_PROVIDER: z.string().optional(),
NX_EMAIL_PROVIDER_API_TOKEN: z.string().optional(), NX_EMAIL_PROVIDER_API_TOKEN: z.string().optional(),
}) })

View file

@ -2,14 +2,14 @@ import { ServerClient as PostmarkServerClient } from 'postmark'
import env from '../../env' import env from '../../env'
export function initializeEmailClient() { export function initializeEmailClient() {
switch (process.env.NX_EMAIL_PROVIDER) { switch (env.NX_EMAIL_PROVIDER) {
case 'postmark': case 'postmark':
if (env.NX_EMAIL_PROVIDER_API_TOKEN) { if (env.NX_EMAIL_PROVIDER_API_TOKEN) {
return new PostmarkServerClient(env.NX_EMAIL_PROVIDER_API_TOKEN) return new PostmarkServerClient(env.NX_EMAIL_PROVIDER_API_TOKEN)
} else { } else {
throw new Error('Missing Postmark API token') return undefined
} }
default: default:
throw new Error('Invalid email provider') return undefined
} }
} }

View file

@ -23,7 +23,9 @@ const envSchema = z.object({
NX_EMAIL_FROM_ADDRESS: z.string().default('account@maybe.co'), NX_EMAIL_FROM_ADDRESS: z.string().default('account@maybe.co'),
NX_EMAIL_REPLY_TO_ADDRESS: z.string().default('support@maybe.co'), NX_EMAIL_REPLY_TO_ADDRESS: z.string().default('support@maybe.co'),
NX_EMAIL_PROVIDER: z.string().optional(),
NX_EMAIL_PROVIDER_API_TOKEN: z.string().optional(), NX_EMAIL_PROVIDER_API_TOKEN: z.string().optional(),
NX_STRIPE_SECRET_KEY: z.string().default('sk_test_REPLACE_THIS'), NX_STRIPE_SECRET_KEY: z.string().default('sk_test_REPLACE_THIS'),
NX_CDN_PRIVATE_BUCKET: z.string().default('REPLACE_THIS'), NX_CDN_PRIVATE_BUCKET: z.string().default('REPLACE_THIS'),

View file

@ -1,10 +1,8 @@
import type { Logger } from 'winston' import type { Logger } from 'winston'
import type { ServerClient as PostmarkServerClient } from 'postmark' import type { ServerClient as PostmarkServerClient } from 'postmark'
import type { MessageSendingResponse } from 'postmark/dist/client/models' import { PostmarkEmailProvider } from './providers'
import type { SharedType } from '@maybe-finance/shared' import type { SharedType } from '@maybe-finance/shared'
import { PostmarkEmailProvider } from './providers/postmark.provider'
export interface IEmailProvider { export interface IEmailProvider {
send(messages: SharedType.PlainEmailMessage): Promise<SharedType.EmailSendingResponse> send(messages: SharedType.PlainEmailMessage): Promise<SharedType.EmailSendingResponse>
send(messages: SharedType.PlainEmailMessage[]): Promise<SharedType.EmailSendingResponse[]> send(messages: SharedType.PlainEmailMessage[]): Promise<SharedType.EmailSendingResponse[]>
@ -23,13 +21,13 @@ export interface IEmailProvider {
} }
export class EmailService implements IEmailProvider { export class EmailService implements IEmailProvider {
private emailProvider: IEmailProvider private emailProvider: IEmailProvider | undefined
constructor( constructor(
private readonly logger: Logger, private readonly logger: Logger,
private readonly client: PostmarkServerClient | undefined, private readonly client: PostmarkServerClient | undefined,
private readonly defaultAddresses: { from: string; replyTo?: string } private readonly defaultAddresses: { from: string; replyTo?: string }
) { ) {
const provider = process.env.EMAIL_PROVIDER const provider = process.env.NX_EMAIL_PROVIDER
switch (provider) { switch (provider) {
case 'postmark': case 'postmark':
@ -40,7 +38,7 @@ export class EmailService implements IEmailProvider {
) )
break break
default: default:
throw new Error('Unsupported email provider') undefined
} }
} }
@ -49,24 +47,34 @@ export class EmailService implements IEmailProvider {
* *
* @returns success boolean(s) * @returns success boolean(s)
*/ */
send(messages: SharedType.PlainEmailMessage): Promise<any> async send(messages: SharedType.PlainEmailMessage): Promise<SharedType.EmailSendingResponse>
send(messages: SharedType.PlainEmailMessage[]): Promise<any[]> async send(messages: SharedType.PlainEmailMessage[]): Promise<SharedType.EmailSendingResponse[]>
send( async send(
messages: SharedType.PlainEmailMessage | SharedType.PlainEmailMessage[] messages: SharedType.PlainEmailMessage | SharedType.PlainEmailMessage[]
): Promise<any | any[]> { ): Promise<SharedType.EmailSendingResponse | SharedType.EmailSendingResponse[]> {
return this.emailProvider.send(messages) if (!this.emailProvider || !this.client) {
//no-op
return undefined as unknown as SharedType.EmailSendingResponse
}
return await this.emailProvider.send(messages)
} }
/** /**
* Sends template email(s) * Sends template email(s)
*/ */
async sendTemplate(messages: SharedType.TemplateEmailMessage): Promise<MessageSendingResponse> async sendTemplate(
messages: SharedType.TemplateEmailMessage
): Promise<SharedType.EmailSendingResponse>
async sendTemplate( async sendTemplate(
messages: SharedType.TemplateEmailMessage[] messages: SharedType.TemplateEmailMessage[]
): Promise<MessageSendingResponse[]> ): Promise<SharedType.EmailSendingResponse[]>
async sendTemplate( async sendTemplate(
messages: SharedType.TemplateEmailMessage | SharedType.TemplateEmailMessage[] messages: SharedType.TemplateEmailMessage | SharedType.TemplateEmailMessage[]
): Promise<MessageSendingResponse | MessageSendingResponse[]> { ): Promise<SharedType.EmailSendingResponse | SharedType.EmailSendingResponse[]> {
if (!this.emailProvider || !this.client) {
//no-op
return undefined as unknown as SharedType.EmailSendingResponse
}
return this.emailProvider.sendTemplate(messages) return this.emailProvider.sendTemplate(messages)
} }
} }

View file

@ -0,0 +1 @@
export * from './postmark.provider'