{"id":22245464,"url":"https://github.com/niiknow/lambda-form","last_synced_at":"2025-07-28T02:32:51.227Z","repository":{"id":33461995,"uuid":"151431490","full_name":"niiknow/lambda-form","owner":"niiknow","description":"A Serverless service to handle form submissions using AWS Lambda.","archived":false,"fork":false,"pushed_at":"2022-06-23T03:07:44.000Z","size":2909,"stargazers_count":3,"open_issues_count":6,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-04T12:35:39.998Z","etag":null,"topics":["aws","contact","contact-form","email-sender","form","lambda","mjml","nunjucks","s3","serverless","submit"],"latest_commit_sha":null,"homepage":"https://niiknow.github.io/lambda-form/demo/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/niiknow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-03T15:04:24.000Z","updated_at":"2022-01-31T19:33:32.000Z","dependencies_parsed_at":"2022-09-13T00:02:55.378Z","dependency_job_id":null,"html_url":"https://github.com/niiknow/lambda-form","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/niiknow/lambda-form","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niiknow%2Flambda-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niiknow%2Flambda-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niiknow%2Flambda-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niiknow%2Flambda-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niiknow","download_url":"https://codeload.github.com/niiknow/lambda-form/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niiknow%2Flambda-form/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267453979,"owners_count":24089854,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","contact","contact-form","email-sender","form","lambda","mjml","nunjucks","s3","serverless","submit"],"created_at":"2024-12-03T05:15:16.967Z","updated_at":"2025-07-28T02:32:50.887Z","avatar_url":"https://github.com/niiknow.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lambda Form\n\u003e A [Serverless](https://serverless.com/) service to handle form submissions using AWS Lambda.\n\nA contact form usually email both Submitter and Form's Creator/Owner.  This Serverless function handle sending of email to both parties.\n\n- Deploy this function and create the associated s3 bucket to store form config and submissions.\n- Create the form config and upload to s3 bucket.  This can be done manually or by creating some kind of admin (outside the scope of this project).\n- Create the front-end of the form and submit to the endpoint.  Example: https://niiknow.github.io/lambda-form/demo/ with backend configuration of https://github.com/niiknow/lambda-form/blob/master/demo/!config.json\n\nFill out the demo form with a real email and wait for result.\n\n**Result**\n1. A form submission record is stored on S3 with the extension '.submit'\n2. All files are stored in the same location under the form-id/submission-id/filename.extension\n3. FUTURE: process stripe transaction.\n\n**S3 Trigger**\n1. At the moment, it sends email to Owner and User.\n\n![](https://raw.githubusercontent.com/niiknow/lambda-form/master/demo/lambda-form.jpg?raw=true)\n\n**Bot/Spam deterrent features**\n- Define a honeypot (hidden input) to protect from generic spam bot - if you run any kind of commentable blog/website, you've probably seen bots that auto-submit these forms with spam.  Honeypot help deny majority of these dumb bots.\n- Define website origins to protect form being use on unknown website.\n- Setup recaptcha to prevent smarter bots.\n\n# Tech Stacks\n**Dev Stack**\n* [debug](https://github.com/visionmedia/debug) - u know, for debugging\n* [aws-sdk-js](https://github.com/aws/aws-sdk-js) - for AWS Lambda function and s3 storage\n* [Serverless](https://serverless.com/) - deployment\n* [Webpack](https://github.com/webpack/webpack) - transform and packaging\n\n**Run Stack**\n* [MJML](https://mjml.io/) and [Nunjucks](https://mozilla.github.io/nunjucks/)- so you can customize your email\n* [nodemailer](https://github.com/nodemailer/nodemailer) - send smtp email (pretty much everybody does smtp, including: ses, sendgrid, mailgun, sendinblue, etc...)\n* [recaptcha2](https://github.com/fereidani/recaptcha2) - to protect your form, it will work with g-recaptcha v3 since it uses the same API endpoint\n\n# Commands\n**To Test**\n```\nnpm install\n./run-data-tests.sh\n```\n\n**To Run/Deploy**\n1. Create s3 bucket\n2. Create environment file from example and set the FORMBUCKET value\n```\ncp env.yml.example env.yml\n```\n3. Deploy\n```\nnpm install\nnpm run deploy\n```\n4. It will deploy dev and give you a URL that you can post to, something like: https://{some-id}.execute-api.us-east-1.amazonaws.com/dev/form/{id}\n5. Update *demo/!config.json* line 2-7 to your SMTP and email\n6. Upload this file to your s3 bucket like so\n```\ndemo/!config.json\n```\n7. Post to your new endpoint, in this case, *demo* is your form {id}\n```\nhttps://{some-id}.execute-api.us-east-1.amazonaws.com/dev/form/demo\n```\n8. Repeat for any new form.  Use random guid as form id to improve performance.\n9. When ready, update serverless.yml to prod and deploy\n```yml\nprovider:\n  name: aws\n  runtime: nodejs8.10\n  stage: dev # change dev to prod\n  region: us-east-1\n```\n\n# Features\n- [x] Per Form configuration, no hardcoding of config or field names\n- [x] No restriction on field name and/or accept any number of inputs\n- [x] Send email to form Submitter and Owner\n- [x] Flexible email subject and body templating with mjml and nunjucks\n- [x] Validate origin domain, recaptcha2, and honeypot\n- [x] Completely serverless, store and read configuration and result on s3 \n- [x] Email sent are replyable, e.g. email sent with 'Reply-To' header *as on behalf of* the Owner/Submitter\n- [x] Support multipart/form-data (file upload) - max payload of 10 MB - impose by [AWS Limit](https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html).\n\n# Why S3 and not directly into some database or sqs/sns?\nBecause it is Serverless and event triggerable.  SQS and SNS has a limit on message size.\n\nYou can use s3 event to trigger followup actions, such as Zapier callback, email subscription, etc...  It can also store this data somewhere like on [Amazon Aurora Serverless](https://aws.amazon.com/rds/aurora/serverless/).\n\nUsually, we want the form to be fast.  The form is already doing a lot of work so we don't want to tack on any unnecessary work.  The benefit of s3 event is to defer the work at a later time, allowing for faster response time.\n\nOther things that can add more delays in the future is support of plugins like Payment Gateways, such as Stripe and/or Paypal.  It may result in pushing email to a later s3 event trigger.\n\n# Project Organization\n```shell\nforms/     - example and for unit testing\nlib/       - helpers\ntemplates/ - email templates\ntests/     - test data\nhandler.js - main form submit handler\nenv.yml    - define environment variable such as FORMBUCKET\n\n# on AWS s3 - bucket\nform-id-folder/!config.json\nform-id-folder/guid-guid-guid-guid.submit\nform-id-folder/result-guid-result-guid.submit\nuse-random-guid-for-best-form-id-performance/!config.json\n```\n\n# Form/Config Schema\n```json\n{\n    \"name\": \"friendly form name, field can be use in email subject\",\n    \"form_id\": \"74d15a89-e358-4980-a29b-0c3daf7fcd95\",\n    \"form_creds\": \"protect form with: username,password\",\n    \"admin_creds\": \"protect form admin page with: username,password\",\n    \"smtp_host\": \"yourdomain.com\",\n    \"smtp_port\": \"587\",\n    \"smtp_user\": \"login@yourdomain.com\",\n    \"smtp_pass\": \"YourPassword\",\n    \"from_email\": \"provide this if smtp_user is not a valid email\",\n    \"recaptcha_field\": \"the form field name, default g-recaptcha-response\",\n    \"recaptcha_key\": \"the site key\",\n    \"recaptcha_secret\": \"the secret key\",\n    \"valid_origins\": \"a comma separated list of valid origins or * for all\",\n    \"honeypot_field\": \"honeypot form field name\",\n    \"redir\": \"https://www.yourdomain.com/thank-you-page\",\n    \"post_url\": \"url to post the result to\",\n    \"post_message\": \"thank you message\",\n    \"business_name\": \"this field can provide company name in email\",\n    \"business_url\": \"this field can provide link in email\",\n    \"image_url\": \"this field can provide logo in email\",\n    \"notify_email\": \"friends@yourdomain.com\",\n    \"notify_subject\": \"New form submit by {{ email }}\",\n    \"notify_body\": \"actual mjml template or empty to use fallback/owner.mjml\",\n    \"email_field\": \"identify the submitter's email, e.g. email field name on the form\",\n    \"email_subject\": \"{{ name }}, thank you for contacting us\",\n    \"email_body\": \"actual mjml template or empty to use fallback/submitter.mjml\",\n    \"pay_gateway\": \"stripe\",\n    \"pay_client_id\": \"stripe client id\",\n    \"pay_secret\": \"stripe secret\",\n    \"pay_public_key\": \"stripe public key\",\n    \"pay_connect_string\": \"additional connection string separate by semicolon\",\n    \"started_at\": \"yyyy-mm-dd when the form start\",\n    \"ended_at\": \"yyyy-mm-dd when the form end\"\n}\n```\n\n# Note\n* This project require AWS S3 private bucket.  Please make sure your bucket is not public or you will expose your SMTP and other credentials.\n* AWS may block or limit sends from port 25, so you should use a different port.\n* Outside of FORMBUCKET, there is no other config on the server. Each form configuration contain it's own SMTP setup.\n* Remember, if you don't use ajax, you should set a redirection (redir property) to provide redirect result.  The front-end can also pass in a \"redir\" query string parameter.\n\n# TODO/Future Enhancements\n- [ ] Filters to include or exclude fields so hidden form field won't come through to the email\n- [ ] Per field validation - possibly use [Indicative](https://indicative.adonisjs.com/) for validation of json\n- [ ] Probably a plugin system to allow plugins enabling base on form config.  Possible plugins:  fallback with SES, more spam validation, ability to track email with google analytic pixel\n- [ ] Payment gateway integration strategy start with Stripe.  Maybe it will be part of plugin system.\n\n# Point of Interest\nSince this is Serverless, this setup can really scale.  It can be use as a component in your Software-as-a-Service *SaaS* platform, like a clone of wufoo.  All you need is an Admin portal with a FormBuilder - hint - [grapejs](https://github.com/artf/grapesjs)\n\n# MIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniiknow%2Flambda-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniiknow%2Flambda-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniiknow%2Flambda-form/lists"}