feat: support SMTP via nodemailer (#17)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { authClient } from "@kan/auth";
|
||||
import { authClient } from "@kan/auth/client";
|
||||
import * as memberRepo from "@kan/db/repository/member.repo";
|
||||
import * as userRepo from "@kan/db/repository/user.repo";
|
||||
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
||||
|
||||
@@ -6,7 +6,7 @@ import superjson from "superjson";
|
||||
import { ZodError } from "zod";
|
||||
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import { initAuth } from "@kan/auth";
|
||||
import { initAuth } from "@kan/auth/server";
|
||||
import { createDrizzleClient } from "@kan/db/client";
|
||||
|
||||
export interface User {
|
||||
|
||||
@@ -4,7 +4,15 @@
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
".": "./src/index.ts",
|
||||
"./client": {
|
||||
"types": "./src/client.ts",
|
||||
"default": "./src/client.ts"
|
||||
},
|
||||
"./server": {
|
||||
"types": "./src/server.ts",
|
||||
"default": "./src/server.ts"
|
||||
}
|
||||
},
|
||||
"license": "GPL-3.0",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1 @@
|
||||
import { initAuth } from "./auth";
|
||||
import { authClient } from "./clients";
|
||||
|
||||
export const name = "auth";
|
||||
|
||||
export { initAuth, authClient };
|
||||
|
||||
1
packages/auth/src/server.ts
Normal file
1
packages/auth/src/server.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { initAuth } from "./auth";
|
||||
@@ -24,12 +24,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-email/components": "^0.0.25",
|
||||
"nodemailer": "^7.0.3",
|
||||
"react-email": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kan/eslint-config": "workspace:*",
|
||||
"@kan/prettier-config": "workspace:*",
|
||||
"@kan/tsconfig": "workspace:*",
|
||||
"@types/nodemailer": "^6.4.17",
|
||||
"eslint": "catalog:",
|
||||
"prettier": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { render } from "@react-email/render";
|
||||
import nodemailer from "nodemailer";
|
||||
|
||||
import JoinWorkspaceTemplate from "./templates/join-workspace";
|
||||
import MagicLinkTemplate from "./templates/magic-link";
|
||||
@@ -10,6 +11,16 @@ const emailTemplates: Record<Templates, React.FC> = {
|
||||
JOIN_WORKSPACE: JoinWorkspaceTemplate,
|
||||
};
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: Number(process.env.SMTP_PORT),
|
||||
secure: true,
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASSWORD,
|
||||
},
|
||||
});
|
||||
|
||||
export const sendEmail = async (
|
||||
to: string,
|
||||
subject: string,
|
||||
@@ -20,22 +31,17 @@ export const sendEmail = async (
|
||||
|
||||
const html = await render(<EmailTemplate {...data} />, { pretty: true });
|
||||
|
||||
const response = await fetch(process.env.EMAIL_URL!, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${process.env.EMAIL_TOKEN}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
from: process.env.EMAIL_FROM,
|
||||
to,
|
||||
subject,
|
||||
html,
|
||||
}),
|
||||
});
|
||||
const options = {
|
||||
from: process.env.EMAIL_FROM,
|
||||
to,
|
||||
subject,
|
||||
html,
|
||||
};
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to send email: ${response.statusText}`);
|
||||
const response = await transporter.sendMail(options);
|
||||
|
||||
if (!response.accepted.length) {
|
||||
throw new Error(`Failed to send email: ${response.response}`);
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
Reference in New Issue
Block a user