Get In Touch
Let's Build Together.
Whether you have a fully-scoped project or just a rough idea — reach out. No pressure, no sales pitch. We respond within 24 hours, guaranteed.
We work directly with every client — no account managers, no handoffs. When you contact Tech Velocity, you're talking to the veteran who runs it.
Response Commitments
Initial response within 24 hours
Project scoping call within 48 hours
Written proposal within 5 business days
Retainer clients: under 4-hour response
Send a Message
Fill out the form and we'll be in touch. All fields marked * are required.
Contact form
Valid name required (2–80 letters).
Valid email address required.
Please select a service.
Message required (10–3000 characters).
0 / 3000
Developer Setup
Activating the Contact Form
The form is fully built and OWASP-hardened. Once your S3 bucket and Zoho account are ready, follow these steps to make it live. The endpoint URL in js/tv-contact.js is the only thing you need to update.
1
Set Up Zoho Mail (Free)
Go to zoho.com/mail → Sign up for Free (Zoho Mail Free Plan).
Add your domain (e.g.
Create the mailbox
Then go to Settings → Mail Accounts → SMTP and note:
Host:
Username:
Password: generate an App Password under Security settings (required if 2FA enabled).
Add your domain (e.g.
techvelocity.dev) → Verify via DNS TXT record in Route 53 or your registrar.Create the mailbox
[email protected].Then go to Settings → Mail Accounts → SMTP and note:
Host:
smtp.zoho.com · Port: 587 · TLS: STARTTLSUsername:
[email protected]Password: generate an App Password under Security settings (required if 2FA enabled).
2
Create AWS Lambda Function
In AWS Console → Lambda → Create Function.
Runtime:
Paste the Lambda code shown below (or deploy via
Add environment variables:
Never hard-code credentials. Use AWS Secrets Manager or Parameter Store for production.
Runtime:
Node.js 20.x · Name: tv-contact-mailerPaste the Lambda code shown below (or deploy via
aws-lambda.zip in this repo).Add environment variables:
ZOHO_USER → [email protected]ZOHO_PASS → your Zoho App PasswordTO_EMAIL → [email protected]ALLOWED_ORIGIN → https://techvelocity.devNever hard-code credentials. Use AWS Secrets Manager or Parameter Store for production.
3
Create API Gateway Endpoint
AWS Console → API Gateway → Create API → HTTP API.
Add integration → Lambda → select
Add route:
Under CORS, set:
Allow-Origin:
Allow-Methods:
Allow-Headers:
Deploy the API → copy the Invoke URL.
It looks like:
Add integration → Lambda → select
tv-contact-mailer.Add route:
POST /contactUnder CORS, set:
Allow-Origin:
https://techvelocity.devAllow-Methods:
POST, OPTIONSAllow-Headers:
Content-TypeDeploy the API → copy the Invoke URL.
It looks like:
https://abc123.execute-api.us-east-1.amazonaws.com
4
Update the Site & Go Live
Open
→ paste your API Gateway Invoke URL +
Also update the CSP header in
Upload all files to S3 → invalidate the CloudFront cache → test the form.
Check your Zoho inbox. Done. Mission complete. ✓
js/tv-contact.js and replace the placeholder:API_ENDPOINT = 'https://YOUR-API-ID.execute-api...'→ paste your API Gateway Invoke URL +
/contactAlso update the CSP header in
contact.html line 10 — replace YOUR-API-ID with your real API Gateway subdomain.Upload all files to S3 → invalidate the CloudFront cache → test the form.
Check your Zoho inbox. Done. Mission complete. ✓
// ── tv-contact-mailer/index.mjs ───────────────────────────────────────── // Deploy as AWS Lambda (Node.js 20.x). // Requires nodemailer — add as Lambda Layer or bundle with npm. // Environment variables (set in Lambda Console → Configuration → Env Vars): // ZOHO_USER → [email protected] // ZOHO_PASS → Zoho App Password (from Zoho Security settings) // TO_EMAIL → [email protected] // ALLOWED_ORIGIN → https://techvelocity.dev import nodemailer from 'nodemailer'; const ALLOWED_ORIGIN = process.env.ALLOWED_ORIGIN || ''; const MAX_FIELD_LEN = { name: 80, email: 254, company: 120, service: 40, budget: 20, message: 3000 }; /* ── Sanitize: strip HTML, trim, enforce max length ── */ function sanitize(str, max) { return String(str || '') .replace(//[<>&"']/g, '') // strip common injection chars .trim() .slice(0, max || 3000); } /* ── Validate email format ── */ function validEmail(e) { return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(e) && e.length <= 254; } export const handler = async (event) => { const cors = { 'Access-Control-Allow-Origin': ALLOWED_ORIGIN, 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Methods': 'POST, OPTIONS', }; /* Preflight */ if (event.requestContext?.http?.method === 'OPTIONS') { return { statusCode: 204, headers: cors, body: '' }; } let body; try { body = JSON.parse(event.body || '{}'); } catch { return { statusCode: 400, headers: cors, body: JSON.stringify({ ok: false }) }; } /* OWASP A07 — Honeypot check */ if (body.website && body.website.length > 0) { return { statusCode: 200, headers: cors, body: JSON.stringify({ ok: true }) }; // silent reject } /* OWASP A03 — Re-sanitize every field server-side */ const name = sanitize(body.name, MAX_FIELD_LEN.name); const email = sanitize(body.email, MAX_FIELD_LEN.email); const company = sanitize(body.company, MAX_FIELD_LEN.company); const service = sanitize(body.service, MAX_FIELD_LEN.service); const budget = sanitize(body.budget, MAX_FIELD_LEN.budget); const message = sanitize(body.message, MAX_FIELD_LEN.message); /* Validate required fields */ if (!name || name.length < 2) return { statusCode: 400, headers: cors, body: JSON.stringify({ ok: false, field: 'name' }) }; if (!validEmail(email)) return { statusCode: 400, headers: cors, body: JSON.stringify({ ok: false, field: 'email' }) }; if (!service) return { statusCode: 400, headers: cors, body: JSON.stringify({ ok: false, field: 'service' }) }; if (!message || message.length < 10) return { statusCode: 400, headers: cors, body: JSON.stringify({ ok: false, field: 'message' }) }; /* ── Send via Zoho SMTP ── */ const transporter = nodemailer.createTransport({ host: 'smtp.zoho.com', port: 587, secure: false, // STARTTLS auth: { user: process.env.ZOHO_USER, pass: process.env.ZOHO_PASS, // Zoho App Password }, tls: { rejectUnauthorized: true }, }); const mailOptions = { from: `"Tech Velocity Site" <${process.env.ZOHO_USER}>`, to: process.env.TO_EMAIL, replyTo: email, // safe — already sanitized above subject: `[TV Contact] ${service} inquiry from ${name}`, text: [ `Name: ${name}`, `Email: ${email}`, `Company: ${company || 'N/A'}`, `Service: ${service}`, `Budget: ${budget || 'N/A'}`, '', `Message:\n${message}`, ].join('\n'), }; try { await transporter.sendMail(mailOptions); /* OWASP A09 — log event (no PII in CloudWatch) */ console.log(JSON.stringify({ event: 'contact_sent', service, ts: new Date().toISOString() })); return { statusCode: 200, headers: cors, body: JSON.stringify({ ok: true }) }; } catch (err) { console.error(JSON.stringify({ event: 'contact_error', msg: err.message }));