Skip to content

dimeloper/contactkit

Repository files navigation

contactkit

Self-hostable contact form backend with a zero-dependency TypeScript SDK. Default email provider is Resend, SMTP is supported, and Railway deployment steps are included below.

Deploy on Railway CI npm License: MIT

Quickstart (Run this repo locally)

This gets the API running locally and verifies it end-to-end.

1. Prerequisites

  • Node.js 20+
  • pnpm 9+
corepack enable
corepack prepare pnpm@9.15.4 --activate

2. Install dependencies

pnpm install

3. Configure environment variables

cp packages/server/.env.example packages/server/.env

Set the minimum required variables in packages/server/.env:

Resend example:

EMAIL_PROVIDER=resend
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxx
MAIL_TO=you@example.com
MAIL_FROM=noreply@yourdomain.com

SMTP (Mailhog/local) example:

EMAIL_PROVIDER=smtp
SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_SECURE=false
MAIL_TO=you@example.com
MAIL_FROM=noreply@example.com

4. Start the server

pnpm --filter @contactkit/server dev

By default, the server starts at http://localhost:3000.

5. Smoke test

Health endpoint:

curl -s http://localhost:3000/health

Contact endpoint (works as-is when TURNSTILE_SECRET is not set):

curl -s -X POST http://localhost:3000/contact \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Jane",
    "email": "jane@example.com",
    "message": "Hello from curl"
  }'

Deploy on Railway

Option A: Deploy button (recommended)

Click the Deploy on Railway button at the top of this README — it provisions everything automatically.

Option B: Manual deploy

  1. Create a new project in Railway and connect this repository.
  2. Add environment variables in Railway:
    • Required: MAIL_TO, MAIL_FROM
    • Provider-specific:
      • Resend: EMAIL_PROVIDER=resend, RESEND_API_KEY=...
      • SMTP: EMAIL_PROVIDER=smtp, SMTP_HOST, SMTP_PORT, optional SMTP_USER, SMTP_PASS, SMTP_SECURE
    • Recommended: ALLOWED_ORIGINS=https://your-frontend-domain.com
  3. Deploy the service.
  4. Verify the deployment:
curl -s https://your-app.up.railway.app/health

SDK Quickstart

Browser

<script type="module">
  import { ContactClient } from 'https://cdn.jsdelivr.net/npm/@contactkit/client/dist/index.js';

  const client = new ContactClient({ baseUrl: 'https://contact.example.com' });

  await client.send({
    name: 'Jane',
    email: 'jane@example.com',
    message: 'Hello!',
    subject: 'Inquiry', // optional
    turnstileToken: '...', // optional
  });
</script>

Node / Edge

import { ContactClient, ContactError } from '@contactkit/client';

const client = new ContactClient({
  baseUrl: 'https://contact.example.com',
  timeoutMs: 10_000, // optional, default 10 s
});

try {
  const { id } = await client.send({
    name: 'Jane',
    email: 'jane@example.com',
    message: 'Hello from Node!',
  });
  console.log('Sent, message id:', id);
} catch (err) {
  if (err instanceof ContactError) {
    console.error(err.code, err.status); // e.g. "validation" 400
  }
}

Configuration at a glance

  • Full env reference: packages/server/.env.example
  • Required in all environments: MAIL_TO, MAIL_FROM
  • Provider selection: EMAIL_PROVIDER=resend (default) or EMAIL_PROVIDER=smtp
  • Resend requires: RESEND_API_KEY
  • SMTP requires: SMTP_HOST, SMTP_PORT (plus optional auth and TLS flags)
  • Security/ops knobs: ALLOWED_ORIGINS, RATE_LIMIT_MAX, RATE_LIMIT_WINDOW, optional TURNSTILE_SECRET

Useful commands

pnpm test
pnpm build
pnpm lint

License

MIT © dimeloper

About

Self-hostable contact form backend with a zero-dependency TypeScript SDK. Resend by default, SMTP optional, one-click Railway deploy.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors