Form Mailer

March 14, 2026 · View on GitHub

CI License: MIT Node.js TypeScript Google Apps Script

日本語

Contact form Web App with Gmail notification. Validates user input server-side and sends email via GmailApp.sendEmail.

Built from apps-script-fleet template.

How It Works

doGet → Serve form.html as Web App
          → User submits form via google.script.run
          → submitForm validates input (form-validator.ts)
          → Build email (mail-builder.ts)
          → Send via GmailApp.sendEmail
          → Return { status, message } to client

Apps Script Projects

EnvironmentLink
devform-mailer-dev
prodform-mailer-prod

Quick Start

1. Create a Google Apps Script Project

Open Google Apps Script → create a new project → copy the scriptId from the project URL.

2. Configure clasp

Set the scriptId in .clasp-dev.json and .clasp-prod.json:

{ "scriptId": "YOUR_SCRIPT_ID", "rootDir": "dist" }

3. Set Admin Email

Change ADMIN_EMAIL in src/index.ts to the email address that should receive contact form submissions.

4. Deploy as Web App

Deploy via the Apps Script editor or clasp deploy with the following settings:

SettingValue
Execute asMe
Who has accessAnyone

The script runs as the deploying user's account, so Gmail sends from that account.

Project Structure

src/
├── index.ts           # GAS entry points: doGet, submitForm (no export keyword)
├── form-validator.ts  # Pure validation logic
├── mail-builder.ts    # HTML email builder with XSS escaping
└── form.html          # Contact form UI (google.script.run AJAX pattern)
test/
├── form-validator.test.ts
└── mail-builder.test.ts

Development

CommandDescription
pnpm run checklint + lint:css + lint:html + typecheck + test (all checks)
pnpm run buildBundle TypeScript + copy assets to dist/
pnpm run testJest with coverage
pnpm run test -- --watchJest watch mode
pnpm run deploycheck → build → deploy to dev
pnpm run deploy:prodcheck → build → deploy to production

CI/CD

CI runs on every push and PR. CD deploys on merge to dev or main — configured via GitHub Actions secrets/variables per environment. See apps-script-fleet docs for details.

Notes

  • Functions in src/index.ts must not have the export keyword — the GAS runtime does not support ES module syntax
  • src/index.ts is excluded from test coverage (GAS globals cannot run in Node.js)
  • Coverage threshold: 80% for all metrics (configurable in jest.config.json)

License

MIT