feat: support SMTP via nodemailer

This commit is contained in:
Henry
2025-06-04 10:16:42 +01:00
parent 3625d702e3
commit 6f4157a108
16 changed files with 70 additions and 33 deletions

View File

@@ -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";

View File

@@ -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 {

View File

@@ -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": {

View File

@@ -1,6 +1 @@
import { initAuth } from "./auth";
import { authClient } from "./clients";
export const name = "auth";
export { initAuth, authClient };

View File

@@ -0,0 +1 @@
export { initAuth } from "./auth";

View File

@@ -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:"

View File

@@ -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;