@katebtech/emails
Reusable email templates, transactional email components, and email-related utilities.
@katebtech/emails
Reusable React Email templates and email sending helpers for Kateb Tech website projects.
This README documents the package purpose, public APIs, import style, package-specific rules, module architecture, and usage examples.
Purpose
@katebtech/emails provides shared email layouts, contact enquiry emails, authentication emails, admin notification emails, and Resend email client helpers.
This package is used by website projects when they need consistent email templates and email delivery logic.
Package Overview
Use @katebtech/emails for:
- reusable React Email templates
- contact form notification emails
- customer confirmation emails
- authentication emails
- admin/business approval emails
- shared email layouts
- shared email footer components
- Resend email client setup
- reusable email sending helpers
File Structure
src
├── auth
│ ├── email-verification.tsx
│ ├── index.ts
│ └── types.ts
├── contact-us
│ ├── BusinessEmail.tsx
│ ├── ConfirmationEmail.tsx
│ ├── EnquiryBody.tsx
│ ├── index.ts
│ ├── sendEnquiryEmails.ts
│ └── types.ts
├── layout
│ ├── EmailFooter.tsx
│ ├── EmailLayout.tsx
│ ├── PoweredByKateb.tsx
│ ├── index.ts
│ └── types.ts
├── _lib
│ ├── constants.ts
│ ├── createEmailSerivce.ts
│ ├── emailClient.ts
│ ├── types.ts
│ └── index.ts
└── projects
└── little-bamiyan
├── activate-business-listing
│ ├── BusinessApprovedEmailBody.tsx
│ ├── index.ts
│ ├── sendActivationEmails.ts
│ ├── sendBusinessApprovedEmail.tsx
│ └── types.ts
└── index.tsImport Style
Use package subpaths when consuming this package from website projects or other packages.
import { EmailLayout } from "@katebtech/emails/layout";
import { EmailVerificationCode } from "@katebtech/emails/auth";
import { sendEnquiryEmails } from "@katebtech/emails/contact-us";
import { createEmailClient } from "@katebtech/emails/lib";Import public types from the same subpath as the API they describe.
import type { OrgInfoEmail } from "@katebtech/emails/lib";
import type { SendEnquiryEmails } from "@katebtech/emails/contact-us";Inside this package, prefer relative imports between local files.
import { EmailLayout } from "../layout";
import type { OrgInfoEmail } from "../_lib";Do not import @katebtech/emails from inside this package.
Package Rules
Folder Purpose
| Folder | Purpose |
|---|---|
src/layout | Shared email layout components used by multiple templates. |
src/_lib | Shared email utilities, constants, and email package types. |
src/auth | Authentication-related emails such as email verification. |
src/contact-us | Contact enquiry email templates and send helpers. |
src/projects/little-bamiyan | Project-specific emails for Little Bamiyan Directory. |
src/projects/little-bamiyan/activate-business-listing | Business approval/activation email templates and send helpers. |
Structure Rule
Use this rule when adding new files:
| Type of code | Put it in |
|---|---|
| Shared email wrapper/layout | src/layout |
| Shared email client/helper | src/_lib |
| Auth email template | src/auth |
| Contact form email template | src/contact-us |
| Contact form send helper | src/contact-us |
| Project workflow email | src/projects/<project>/<workflow> |
| Email-specific types | types.ts in the module folder |
Do not place website-specific server actions inside this package.
A website server action can import templates and send helpers from this package, but the server action itself should stay inside the website project.
Design Principles
This package should contain reusable email templates and email sending helpers.
It should stay focused on email composition and delivery.
What Belongs in @katebtech/emails
Use this package for:
- React Email templates
- reusable email layouts
- reusable email footer components
- email body components
- confirmation emails
- admin notification emails
- auth emails
- approval/activation emails
- reusable send helpers
- Resend client setup
- email-specific TypeScript types
Email Package Rule
If the code builds or sends an email, it can belong in @katebtech/emails.
If the code receives a form submission, reads from a database, verifies permissions, or controls website business logic, keep it in the website project.
Good rule:
Website project = server actions, database, env vars, business rules
@katebtech/emails = email templates and send helpersModule Documentation
Shared Email Layout
Shared email layout components live in:
src/layout
├── EmailFooter.tsx
├── EmailLayout.tsx
├── PoweredByKateb.tsx
├── index.ts
└── types.tsThese components provide the common email wrapper, footer, and Kateb Tech branding used by email templates across the package.
Use this folder for email layout components and layout-related types that are shared by more than one email template.
EmailLayout
Path: src/layout/EmailLayout.tsx
Purpose: Provides the main reusable wrapper for email templates.
EmailLayout creates the full email document structure using React Email components.
It includes:
<Html><Head><Preview><Body>- main email container
- optional title section
- optional intro note
- main email content area
- shared organisation footer
- Kateb Tech powered-by branding
Import:
import { EmailLayout } from "@katebtech/emails/layout";Basic usage:
import { Text } from "@react-email/components";
import { EmailLayout } from "@katebtech/emails/layout";
export const ExampleEmail = () => {
return (
<EmailLayout
orgInfo={{
name: "Kateb Tech",
domain: "katebtech.com.au",
orgNameHz: "کاتب تک",
address: "Dandenong VIC, Australia",
email: "info@example.com",
phone: "0400 000 000",
}}
preview="New enquiry received"
title="New website enquiry"
introNote="A visitor submitted the enquiry form."
>
<Text>Hello, this is the email content.</Text>
</EmailLayout>
);
};RTL usage:
<EmailLayout
orgInfo={orgInfo}
preview="پیام جدید دریافت شد"
title="پیام جدید"
introNote="یک پیام جدید از وبسایت دریافت شد."
dir="rtl"
>
<Text>متن ایمیل اینجا قرار میگیرد.</Text>
</EmailLayout>Props:
| Prop | Type | Default | Description |
|---|---|---|---|
orgInfo | OrgInfoEmail | Required | Organisation details used by the shared layout and footer. |
preview | string | Required | Email preview text shown by email clients. |
title | string | undefined | Optional email title rendered near the top of the email. |
children | ReactNode | Required | Main email body content. |
introNote | string | undefined | Optional short note displayed under the title. |
dir | "ltr" | "rtl" | "ltr" | Text direction for the email document. |
Related type:
import type { EmailLayoutProps } from "@katebtech/emails/layout";Notes:
- Uses
@react-email/components. - Uses
EmailFooterautomatically. - Uses
PoweredByKatebautomatically. - Use this wrapper for most email templates.
- Do not place website-specific business logic inside this component.
- Pass website/organisation data through props.
EmailFooter
Path: src/layout/EmailFooter.tsx
Purpose: Renders a reusable organisation footer for email templates.
It displays:
- organisation favicon, built from
domain - organisation name
- optional Hazaragi organisation name
- address
- email link
- phone number
- website link, built from
domain
Import:
import { EmailFooter } from "@katebtech/emails/layout";Basic usage:
<EmailFooter
name="Kateb Tech"
domain="katebtech.com.au"
orgNameHz="کاتب تک"
address="Dandenong VIC, Australia"
email="info@example.com"
phone="0400 000 000"
/>Props:
EmailFooter accepts the OrgInfoEmail fields directly.
Related type:
import type { OrgInfoEmail } from "@katebtech/emails/lib";Notes:
- Uses
ImgandSectionfrom@react-email/components. - Email and website are rendered as links.
- Phone number, address, and Hazaragi organisation name are optional.
- This component is automatically included inside
EmailLayout, so most templates do not need to use it directly.
PoweredByKateb
Path: src/layout/PoweredByKateb.tsx
Purpose: Renders a small “Powered by Kateb Tech” branding block at the bottom of email templates.
It includes:
- Kateb Tech logo
- “Powered by Kateb Tech” label
- link to the Kateb Tech website
- Kateb Tech brand colours
Import:
import { PoweredByKateb } from "@katebtech/emails/layout";Basic usage:
<PoweredByKateb />Notes:
- Uses
KATEB_TECH_LOGOfrom@katebtech/core. - Uses
Img,Link,Section, andTextfrom@react-email/components. - This component is automatically included inside
EmailLayout. - Most email templates do not need to use it directly.
- Keep this component generic and reusable across all Kateb Tech email templates.
OrgInfoEmail
Path: src/_lib/types.ts
Purpose: Defines the organisation information used by shared email layout components.
OrgInfoEmail is used by:
EmailLayoutEmailFooter- email templates that need organisation branding/contact details
Import:
import type { OrgInfoEmail } from "@katebtech/emails/lib";Type:
type OrgInfoEmail = {
email: string;
name: string;
domain: string;
orgNameHz?: string;
address?: string;
phone?: string;
};Example:
const orgInfo: OrgInfoEmail = {
name: "Kateb Tech",
domain: "katebtech.com.au",
orgNameHz: "کاتب تک",
address: "Dandenong VIC, Australia",
email: "info@example.com",
phone: "0400 000 000",
};Field meaning:
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Contact email shown in the footer. |
name | string | Yes | Organisation name in English. |
domain | string | Yes | Domain used for the website link and favicon path. |
orgNameHz | string | No | Organisation name in Hazaragi script. |
address | string | No | Organisation address shown in the email footer. |
phone | string | No | Phone number shown in the footer. |
Contact Us Emails
Contact enquiry emails live in:
src/contact-us
├── BusinessEmail.tsx
├── ConfirmationEmail.tsx
├── EnquiryBody.tsx
├── index.ts
├── sendEnquiryEmails.ts
└── types.tsThis module provides reusable email templates and send helpers for website contact/enquiry forms.
Use this module when a website has a standard enquiry flow where:
- A visitor submits a contact/enquiry form.
- The business receives a notification email.
- The visitor receives a confirmation email.
- Both emails share the same enquiry details and organisation branding.
sendEnquiryEmails
Path: src/contact-us/sendEnquiryEmails.ts
Purpose: Sends both enquiry emails for a contact form submission.
It sends:
- business/admin notification email
- visitor/customer confirmation email
Internally, it calls:
sendBusinessEmailsendConfirmationEmail
Import:
import { sendEnquiryEmails } from "@katebtech/emails/contact-us";Basic usage inside a website server action:
"use server";
import { sendEnquiryEmails } from "@katebtech/emails/contact-us";
export async function submitContactForm(formData: FormData) {
await sendEnquiryEmails({
apiKey: process.env.RESEND_API_KEY!,
orgInfo: {
name: "Kateb Tech",
domain: "katebtech.com.au",
orgNameHz: "کاتب تک",
address: "Dandenong VIC, Australia",
email: "info@example.com",
phone: "0400 000 000",
},
enquiry: {
fullName: "Visitor Name",
email: "visitor@example.com",
contactNumber: "0400 000 000",
qMessage: "I would like to request a quote.",
},
});
}Return value:
Promise<{ message: string }>;Example success message:
Thanks! We have received your enquiry.If the visitor confirmation email fails but the business email still runs, the returned message may include:
(Heads-up: we couldn’t send the confirmation email.)Notes:
- Uses
Promise.allSettled()so one failed email does not automatically stop the other email from completing. - Logs business/admin email failure.
- Logs visitor confirmation email failure.
- Returns a user-friendly message.
- The website project should validate form data before calling this helper.
- The website project should provide the Resend API key through environment variables.
sendBusinessEmail
Path: src/contact-us/BusinessEmail.tsx
Purpose: Sends the business/admin notification email when a website visitor submits an enquiry.
This email is sent to:
data.orgInfo.email;It uses the visitor’s email as the reply-to address:
replyTo: data.enquiry.email;This allows the business to reply directly to the visitor from their email client.
Import:
import { sendBusinessEmail } from "@katebtech/emails/contact-us";Basic usage:
await sendBusinessEmail({
apiKey: process.env.RESEND_API_KEY!,
orgInfo,
enquiry: {
fullName: "Visitor Name",
email: "visitor@example.com",
contactNumber: "0400 000 000",
qMessage: "I need help with a website.",
},
});Email details:
| Field | Value |
|---|---|
from | WEB_ENQUIRY |
to | data.orgInfo.email |
replyTo | data.enquiry.email |
subject | Web Enquiry - ${data.enquiry.fullName} |
react | <EnquiryBody data={data} title="New Web Enquiry" /> |
Notes:
- Uses
createEmailClient(data.apiKey). - Uses
WEB_ENQUIRYfromsrc/_lib/constants. - Uses
EnquiryBodyas the email body. - Logs and rethrows errors when sending fails.
- This is a server-side send helper, not just a React template.
sendConfirmationEmail
Path: src/contact-us/ConfirmationEmail.tsx
Purpose: Sends a confirmation email back to the visitor after they submit an enquiry.
This email is sent to:
data.enquiry.email;It uses the organisation email as the reply-to address:
replyTo: data.orgInfo.email;Import:
import { sendConfirmationEmail } from "@katebtech/emails/contact-us";Basic usage:
await sendConfirmationEmail({
apiKey: process.env.RESEND_API_KEY!,
orgInfo,
enquiry: {
fullName: "Visitor Name",
email: "visitor@example.com",
contactNumber: "0400 000 000",
qMessage: "I need help with a website.",
},
});Email details:
| Field | Value |
|---|---|
from | FROM_KATEBTECH |
to | data.enquiry.email |
replyTo | data.orgInfo.email |
subject | Your enquiry is sent to – ${data.orgInfo.name} |
react | <EnquiryBody dontReplyNote /> |
Notes:
- Uses
createEmailClient(data.apiKey). - Uses
FROM_KATEBTECHfromsrc/_lib/constants. - Uses
EnquiryBodyas the email body. - Shows a “do not reply” note.
- Logs and rethrows errors when sending fails.
- This is a server-side send helper.
EnquiryBody
Path: src/contact-us/EnquiryBody.tsx
Purpose: Renders the shared React Email body for enquiry emails.
It is used by:
sendBusinessEmailsendConfirmationEmail
It displays:
- visitor full name
- visitor email
- visitor phone number
- enquiry message
- optional “do not reply” note
Import:
import { EnquiryBody } from "@katebtech/emails/contact-us";Basic usage:
<EnquiryBody data={data} title="New Web Enquiry" />Confirmation usage with do-not-reply note:
<EnquiryBody
data={data}
title="Your enquiry has been sent"
dontReplyNote
orgName={data.orgInfo.name}
/>Props:
EnquiryBodyProps is a union type.
When dontReplyNote is true, orgName is required:
type EnquiryBodyProps = {
data: SendEnquiryEmails;
title: string;
dontReplyNote: true;
orgName: string;
};When dontReplyNote is false or omitted, orgName must not be passed:
type EnquiryBodyProps = {
data: SendEnquiryEmails;
title: string;
dontReplyNote?: false;
orgName?: never;
};Notes:
- Uses
EmailLayoutfromsrc/layout. - Uses
HrandTextfrom@react-email/components. - Uses
data.orgInfofor organisation branding. - Uses
data.enquiryfor visitor enquiry details. - The do-not-reply note is useful for confirmation emails sent from a no-reply or system address.
SendEnquiryEmails
Path: src/contact-us/types.ts
Purpose: Defines the complete payload required to send enquiry emails.
Import:
import type { SendEnquiryEmails } from "@katebtech/emails/contact-us";Type:
type SendEnquiryEmails = {
enquiry: {
fullName: string;
email: string;
contactNumber?: string;
qMessage: string;
};
apiKey: string;
orgInfo: OrgInfoEmail;
};Field meaning:
| Field | Type | Description |
|---|---|---|
enquiry.fullName | string | Visitor’s full name. |
enquiry.email | string | Visitor’s email address. |
enquiry.contactNumber | string | undefined | Optional visitor phone number. |
enquiry.qMessage | string | Visitor’s enquiry message. |
apiKey | string | Resend API key supplied by the website project. |
orgInfo | OrgInfoEmail | Organisation branding and contact details. |
OrgInfoEmail source:
import type { OrgInfoEmail } from "@katebtech/emails/lib";OrgInfoEmail belongs to the shared email library module because it is used across layout components and send helpers.
EnquiryBodyProps
Path: src/contact-us/types.ts
Purpose:
Defines props for the shared EnquiryBody component.
Import:
import type { EnquiryBodyProps } from "@katebtech/emails/contact-us";Type:
type EnquiryBodyProps =
| {
data: SendEnquiryEmails;
title: string;
dontReplyNote: true;
orgName: string;
}
| {
data: SendEnquiryEmails;
title: string;
dontReplyNote?: false;
orgName?: never;
};Why it is a union type:
This type prevents accidental usage like:
<EnquiryBody data={data} title="New Web Enquiry" dontReplyNote />If dontReplyNote is true, TypeScript requires:
orgName={data.orgInfo.name}This keeps the do-not-reply note complete and avoids missing organisation names in confirmation emails.
Website usage pattern
A website project should usually do this:
- Validate form data in the website server action.
- Build a
SendEnquiryEmailspayload. - Call
sendEnquiryEmails. - Return the result message to the form state.
Example:
"use server";
import { sendEnquiryEmails } from "@katebtech/emails/contact-us";
import type { SendEnquiryEmails } from "@katebtech/emails/contact-us";
export async function submitContactForm(formData: FormData) {
const payload: SendEnquiryEmails = {
apiKey: process.env.RESEND_API_KEY!,
orgInfo: {
name: "Kateb Tech",
domain: "katebtech.com.au",
orgNameHz: "کاتب تک",
address: "Dandenong VIC, Australia",
email: "info@example.com",
phone: "0400 000 000",
},
enquiry: {
fullName: String(formData.get("fullName") ?? ""),
email: String(formData.get("email") ?? ""),
contactNumber: String(formData.get("contactNumber") ?? ""),
qMessage: String(formData.get("qMessage") ?? ""),
},
};
return sendEnquiryEmails(payload);
}Auth Emails
Authentication emails live in:
src/auth
├── email-verification.tsx
├── index.ts
└── types.tsThis module provides reusable email templates for authentication-related flows.
Currently, it includes an email verification code template.
EmailVerificationCode
Path: src/auth/email-verification.tsx
Purpose: Renders an email verification code email.
Use this email when a website needs to send a short verification code to confirm a user’s email address.
It displays:
- English heading
- recipient greeting
- short English instruction
- optional Hazaragi/Dari instruction when
otherLanguageKeyis"HZ" - verification code
- English ignore-this-email note
- optional Hazaragi/Dari ignore-this-email note when
otherLanguageKeyis"HZ" - Kateb Tech powered-by branding
Import:
import { EmailVerificationCode } from "@katebtech/emails/auth";Basic usage:
<EmailVerificationCode
fullName="Baz Rahimi"
code="123456"
otherLanguageKey="HZ"
/>When fullName is not provided, the greeting falls back to:
Hi there,EmailVerificationCodeProps
Path: src/auth/types.ts
Purpose: Defines the public props type for the email verification template.
Import:
import type { EmailVerificationCodeProps } from "@katebtech/emails/auth";Type:
type EmailVerificationCodeProps = {
fullName?: string;
code: string;
otherLanguageKey: OtherLanguageKey;
};Props:
| Prop | Type | Default | Description |
|---|---|---|---|
fullName | string | undefined | Optional recipient name used in the greeting. |
code | string | Required | Verification code shown in the email, usually a 6-digit code. |
otherLanguageKey | OtherLanguageKey | Required | Pass the supported secondary language key. Currently "HZ" renders the Hazaragi/Dari RTL text. |
OtherLanguageKey comes from @katebtech/core. At the moment, the supported value is "HZ".
Email content
The template includes this English instruction:
Use the 6-digit code below to confirm your email address. It expires in 10 minutes.It also includes Hazaragi/Dari RTL instructions for bilingual users when otherLanguageKey is "HZ".
The verification code is displayed in a styled code box with:
- large font size
- bold text
- extra letter spacing
- light border
- light background
Dark mode handling
This email includes light-mode rendering hints inside <Head>:
<meta name="color-scheme" content="light" />
<meta name="supported-color-schemes" content="light" />It also includes inline CSS to reduce unwanted dark-mode colour inversion in email clients.
Important classes:
email-container
email-code-box
email-footerThese are used to keep the background and text colours stable across email clients where possible.
Powered by Kateb Tech
EmailVerificationCode includes:
<PoweredByKateb />from:
src/layout/PoweredByKateb.tsxThis means the email automatically includes the Kateb Tech branding block at the bottom.
Typical website usage
A website project should usually do this:
- Generate the verification code in the website project.
- Save or store the code securely with an expiry time.
- Send the email using the website’s email sending logic.
- Render
EmailVerificationCodeas the React email body.
Example:
"use server";
import { EmailVerificationCode } from "@katebtech/emails/auth";
import { createEmailClient } from "@katebtech/emails/lib";
import type { OtherLanguageKey } from "@katebtech/core/content";
export async function sendVerificationCodeEmail({
apiKey,
to,
fullName,
code,
otherLanguageKey,
}: {
apiKey: string;
to: string;
fullName?: string;
code: string;
otherLanguageKey: OtherLanguageKey;
}) {
const emailClient = createEmailClient(apiKey);
return emailClient.emails.send({
from: "Kateb Tech <no-reply@example.com>",
to: [to],
subject: "Your verification code",
react: (
<EmailVerificationCode
fullName={fullName}
code={code}
otherLanguageKey={otherLanguageKey}
/>
),
});
}Auth email module rules
Use these rules when changing auth email templates.
What belongs here:
email verification templates
password reset email templates
login code email templates
account confirmation email templates
auth email props/typesProject-Specific Emails
Project-specific emails live in:
src/projects
└── little-bamiyan
├── activate-business-listing
│ ├── BusinessApprovedEmailBody.tsx
│ ├── index.ts
│ ├── sendActivationEmails.ts
│ ├── sendBusinessApprovedEmail.tsx
│ └── types.ts
└── index.tsThe src/projects folder is used for email workflows that belong to a specific Kateb Tech project.
Use this folder when an email is not generic enough to belong in auth, contact-us, or layout.
Current project modules:
little-bamiyan
Project folder rule
Use this structure for project-specific emails:
src/projects/<project-name>/<workflow-name>Examples:
src/projects/little-bamiyan/activate-business-listing
src/projects/kateb-offices/booking-confirmation
src/projects/hazara-cultural-association/event-registrationUse project folders for emails that are tied to one product, platform, or client workflow.
What belongs in src/projects
Good examples:
Little Bamiyan business approval emails
Little Bamiyan listing activation emails
project-specific admin notification emails
project-specific booking emails
project-specific event emails
project-specific directory emailsLittle Bamiyan Emails
Little Bamiyan emails live in:
src/projects/little-bamiyanCurrent workflow:
activate-business-listingThis workflow sends an email when a business listing is approved and activated on Little Bamiyan Directory.
activate-business-listing
Path: src/projects/little-bamiyan/activate-business-listing
Purpose: Provides the email body and send helpers for the Little Bamiyan business listing approval workflow.
Use this workflow when a submitted business listing has been reviewed and approved.
It can:
- send an approval email to the business owner
- include the approved business listing URL
- include English and Hazaragi/Dari content
- use the shared
EmailLayout - use organisation branding from
orgInfo - return a friendly status message to the admin workflow
BusinessApprovedEmailBody
Path: src/projects/little-bamiyan/activate-business-listing/BusinessApprovedEmailBody.tsx
Purpose: Renders the email body for a business listing approval email.
It displays:
- greeting using the business name
- English approval message
- Hazaragi approval message
- listing URL
- instruction to contact the organisation if details need updating
- do-not-reply note
- shared email footer and Kateb Tech branding through
EmailLayout
Import:
import { BusinessApprovedEmailBody } from "@katebtech/emails/projects/little-bamiyan";Basic usage:
<BusinessApprovedEmailBody data={data} />Notes:
- Uses
EmailLayoutfromsrc/layout. - Uses
Hr,Link, andTextfrom@react-email/components. - Uses RTL styling for Hazaragi/Dari text.
- Uses
data.businessActivation.fullUrlwhen available. - Uses
data.orgInfofor organisation branding.
BusinessApprovedEmailBodyProps
Path: src/projects/little-bamiyan/activate-business-listing/types.ts
Purpose: Defines props for the business approval email body component.
Import:
import type { BusinessApprovedEmailBodyProps } from "@katebtech/emails/projects/little-bamiyan";Type:
type BusinessApprovedEmailBodyProps = {
data: SendActivationEmails;
};sendBusinessApprovedEmail
Path: src/projects/little-bamiyan/activate-business-listing/sendBusinessApprovedEmail.tsx
Purpose: Sends one business listing approval email to the approved business owner.
Import:
import { sendBusinessApprovedEmail } from "@katebtech/emails/projects/little-bamiyan";Basic usage:
await sendBusinessApprovedEmail({
apiKey: process.env.RESEND_API_KEY!,
orgInfo,
businessActivation: {
name: "Example Business",
email: "owner@example.com",
fullUrl: "https://www.littlebamiyan.com.au/business/example-business",
},
});Email details:
| Field | Value |
|---|---|
from | Little Bamiyan Directory <handler@katebtech.com.au> |
to | data.businessActivation.email |
replyTo | data.orgInfo.email |
subject | Your business listing has been approved – ${data.orgInfo.name} |
react | <BusinessApprovedEmailBody data={data} /> |
Notes:
- Uses
createEmailClient(data.apiKey). - Sends to the approved business owner.
- Uses the organisation email as the reply-to address.
- Throws the error if sending fails.
sendActivationEmails
Path: src/projects/little-bamiyan/activate-business-listing/sendActivationEmails.ts
Purpose: Runs the business listing activation email workflow.
Currently it sends:
- business approval email to the business owner
Import:
import { sendActivationEmails } from "@katebtech/emails/projects/little-bamiyan";Basic usage:
const result = await sendActivationEmails({
apiKey: process.env.RESEND_API_KEY!,
orgInfo,
businessActivation: {
name: "Example Business",
email: "owner@example.com",
fullUrl: "https://www.littlebamiyan.com.au/business/example-business",
},
});
console.log(result.message);Return value:
Promise<{ message: string }>;Default success message:
Business status updated.If the approval email fails:
Business status updated. (Listing was approved, but approval email could not be sent.)Notes:
- Uses
Promise.allSettled(). - The workflow can be extended later if activation needs to send more than one email.
- The website/admin project should update the business listing status in the database.
- This helper only handles email sending.
SendActivationEmails
Path: src/projects/little-bamiyan/activate-business-listing/types.ts
Purpose: Defines the payload required for the Little Bamiyan business listing activation email workflow.
Import:
import type { SendActivationEmails } from "@katebtech/emails/projects/little-bamiyan";Type:
type SendActivationEmails = {
businessActivation: {
name: string;
email: string;
fullUrl: string;
};
apiKey: string;
orgInfo: OrgInfoEmail;
};Field meaning:
| Field | Type | Description |
|---|---|---|
businessActivation.name | string | Approved business name. |
businessActivation.email | string | Business owner email address. |
businessActivation.fullUrl | string | Public URL of the approved listing. |
apiKey | string | Resend API key supplied by the website/admin project. |
orgInfo | OrgInfoEmail | Organisation branding and contact details. |
Website/admin usage pattern
A website or admin project should usually do this:
- Admin approves the business listing in the database.
- Website/admin project builds the
SendActivationEmailspayload. - Website/admin project calls
sendActivationEmails. - Website/admin project displays the returned message to the admin user.
Example:
"use server";
import { sendActivationEmails } from "@katebtech/emails/projects/little-bamiyan";
import type { SendActivationEmails } from "@katebtech/emails/projects/little-bamiyan";
export async function approveBusinessListing() {
// 1. Update listing status in the database inside the website/admin project.
const payload: SendActivationEmails = {
apiKey: process.env.RESEND_API_KEY!,
orgInfo: {
name: "Little Bamiyan Directory",
domain: "littlebamiyan.com.au",
orgNameHz: "دایرکتوری لیتل بامیان",
address: "Melbourne, Australia",
email: "info@littlebamiyan.com.au",
phone: "0400 000 000",
},
businessActivation: {
name: "Example Business",
email: "owner@example.com",
fullUrl: "https://www.littlebamiyan.com.au/business/example-business",
},
};
return sendActivationEmails(payload);
}Email Library Helpers
Email library helpers live in:
src/_lib
├── constants.ts
├── createEmailSerivce.ts
├── emailClient.ts
├── types.ts
└── index.tsThis module provides shared utilities used by email send helpers across the package.
createEmailClient
Path: src/_lib/emailClient.ts
Purpose: Creates a Resend email client using the API key provided by the website project.
Import:
import { createEmailClient } from "@katebtech/emails/lib";Basic usage:
const emailClient = createEmailClient(process.env.RESEND_API_KEY!);Send email example:
import { createEmailClient } from "@katebtech/emails/lib";
const emailClient = createEmailClient(process.env.RESEND_API_KEY!);
await emailClient.emails.send({
from: "Web Enquiry <handler@katebtech.com.au>",
to: ["business@example.com"],
subject: "New enquiry",
react: <div>Hello</div>,
});Implementation:
import { Resend } from "resend";
export const createEmailClient = (apiKey: string) => {
return new Resend(apiKey);
};Notes:
- Uses the
resendpackage. - The API key must come from the website project.
- Do not hard-code the Resend API key inside this package.
- Website projects should usually pass
process.env.RESEND_API_KEY. - This helper keeps Resend setup consistent across email modules.
createEmailService
Path: src/_lib/createEmailSerivce.ts
Purpose: Creates a small email service wrapper around Resend with reusable sender identity helpers.
Use this when a website or project needs a Resend client and wants consistent from values built from the shared Kateb Tech handler address.
Import:
import { createEmailService } from "@katebtech/emails/lib";Basic usage:
const emailService = createEmailService({
apiKey: process.env.RESEND_API_KEY!,
organisationName: "Little Bamiyan Directory",
});
await emailService.resend.emails.send({
from: emailService.from.organisation,
to: ["owner@example.com"],
subject: "Your business listing has been approved",
react: <div>Your listing is live.</div>,
});Sender helpers:
| Helper | Returns |
|---|---|
from.organisation | ${organisationName} <handler@katebtech.com.au> |
from.formSubmission() | ${formName} Submission <handler@katebtech.com.au> |
from.custom() | ${senderName} <handler@katebtech.com.au> |
Notes:
- Throws
Email sender name is required.when a custom sender name is blank. - Trims sender names before building the final
fromvalue. - Uses the shared
KATEB_EMAIL_HANDLERconstant fromsrc/_lib/constants. - The source file is currently named
createEmailSerivce.ts, while the exported helper iscreateEmailService.
KATEB_EMAIL_HANDLER
Path: src/_lib/constants.ts
Purpose:
Shared Kateb Tech handler email address used to build sender identities.
Import:
import { KATEB_EMAIL_HANDLER } from "@katebtech/emails/lib";Value:
export const KATEB_EMAIL_HANDLER = "<handler@katebtech.com.au>";Notes:
- Used by shared sender constants and
createEmailService. - Use this to build project-specific sender identities that still send through the Kateb Tech handler address.
FROM_KATEBTECH
Path: src/_lib/constants.ts
Purpose: Default sender identity for emails sent from Kateb Tech.
Import:
import { FROM_KATEBTECH } from "@katebtech/emails/lib";Value:
export const FROM_KATEBTECH = "Kateb Tech <handler@katebtech.com.au>";Typical usage:
await emailClient.emails.send({
from: FROM_KATEBTECH,
to: ["user@example.com"],
subject: "Your verification code",
react: <EmailVerificationCode code="123456" otherLanguageKey="HZ" />,
});Notes:
- Use this for general Kateb Tech system emails.
- Good examples include verification emails, confirmation emails, and platform notices.
- For project-specific senders, create a project-specific sender constant inside the project module.
WEB_ENQUIRY
Path: src/_lib/constants.ts
Purpose: Default sender identity for website enquiry emails.
Import:
import { WEB_ENQUIRY } from "@katebtech/emails/lib";Value:
export const WEB_ENQUIRY = "Web Enquiry <handler@katebtech.com.au>";Typical usage:
await emailClient.emails.send({
from: WEB_ENQUIRY,
to: ["business@example.com"],
replyTo: "visitor@example.com",
subject: "Web Enquiry - Visitor Name",
react: <EnquiryBody data={data} title="New Web Enquiry" />,
});Notes:
- Use this for contact form notifications sent to a business/admin.
- The
replyToshould usually be the visitor’s email address. - This allows the business to reply directly to the visitor.