{"id":17642540,"url":"https://github.com/torrayne/formailer","last_synced_at":"2025-05-06T21:47:07.629Z","repository":{"id":47337340,"uuid":"327481160","full_name":"torrayne/formailer","owner":"torrayne","description":"An email library for your Jamstack site","archived":false,"fork":false,"pushed_at":"2024-05-25T01:41:27.000Z","size":57807,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-19T15:33:46.730Z","etag":null,"topics":["email","forms","jamstack","jamstack-architecture","multipart-forms","netlify","smtp"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/torrayne.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-07T02:25:25.000Z","updated_at":"2024-08-09T16:12:02.000Z","dependencies_parsed_at":"2024-11-09T07:15:34.662Z","dependency_job_id":null,"html_url":"https://github.com/torrayne/formailer","commit_stats":{"total_commits":157,"total_committers":2,"mean_commits":78.5,"dds":"0.019108280254777066","last_synced_commit":"fd900dabca68d2fd2a951a6cb8eec07404d8d809"},"previous_names":["torrayne/formailer","djatwood/formailer"],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/torrayne%2Fformailer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/torrayne%2Fformailer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/torrayne%2Fformailer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/torrayne%2Fformailer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/torrayne","download_url":"https://codeload.github.com/torrayne/formailer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252776476,"owners_count":21802461,"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","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":["email","forms","jamstack","jamstack-architecture","multipart-forms","netlify","smtp"],"created_at":"2024-10-23T08:04:22.740Z","updated_at":"2025-05-06T21:47:07.602Z","avatar_url":"https://github.com/torrayne.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Formailer\n\n![Go](https://github.com/torrayne/formailer/workflows/Go/badge.svg)\n\n![Screenshot](img.png)\n\nIf you need your contact form to send you an email from your Jamstack site, Formailer is the serverless library for you! Out of the box Formailer supports redirects, reCAPTCHA, custom email templates, and custom handlers.\n\n## Quickstart\n[View Documenation](https://pkg.go.dev/github.com/torrayne/formailer)\n\nFormailer tries to require as little boilerplate as possible. Create a form, add some emails, and run a handler.\n```go\nimport (\n\t\"github.com/torrayne/formailer\"\n\t\"github.com/torrayne/formailer/handlers\"\n\t\n\t// For Netlify\n\t\"github.com/aws/aws-lambda-go/lambda\"\n)\n\nfunc main() {\n\tcontact := formailer.New(\"Contact\")\n\tcontact.AddEmail(formailer.Email{\n\t\tTo:      \"info@domain.com\",\n\t\tFrom:    `\"Company\" \u003cnoreply@domain.com\u003e`,\n\t\tSubject: \"New Contact Submission\",\n\t})\n\n\t// Vercel\n\thandlers.Vercel(formailer.DefaultConfig, w, r)\n\t// Netlify\n\tlambda.Start(handlers.Netlify(formailer.DefaultConfig))\n}\n```\nIf you want to use your own handler that's not a problem either. [View an example handler](#user-content-custom-handlers).\n\nThen you update your form. So that we can use the correct form config you need to add the form id as a hidden input with the name `_form_name`. Note the form id is case-insensitive.\n\nFormailer supports submitting forms as `application/x-www-form-urlencoded`, `multipart/form-data`, or `application/json`.\n\nThe built-in handlers come with built in Google reCaptcha verification if you add a `RECAPTCHA_SECRET` to your environment variables.\n```html\n\u003c!-- html form --\u003e\n\u003cinput type=\"hidden\" name=\"_form_name\" value=\"contact\"\u003e\n\u003cbutton class=\"g-recaptcha\" data-sitekey=\"reCAPTCHA_site_key\" data-callback='onSubmit' data-action='submit'\u003eSubmit\u003c/button\u003e\n```\n```javascript\n// JSON object\n{\n\t...\n\t\"_form_name\": \"contact\",\n}\n```\n\n## Customization\n\nYou can customize Formailer to suit your needs. You can add as many forms as you'd like. As long as they have unique ids. Each form can have it's own email template and SMTP settings. But if you want to set defaults for everything you can.\n### SMTP\n\nAll of your SMTP variables must be saved in the environment. You can add as many configs as you have emails. And you can save a default config to fallback on. Note that if you have default config you don't need to specify every option again. Any missing options will fallback to the default.\n\nIf you build your own handler you can store the config anywhere you want. Just pass a `*mail.SMTPServer` to `submission.Send(server)` and you're good to go.\n\n```env\n# Default\nSMTP_HOST=mail.example.com\nSMTP_PORT=587\nSMTP_USER=noreply@example.com\nSMTP_PASS=mysupersecretpassword\n\n# Overrides\n# _HOST and _PORT will fallback to the default above\nSMTP_EMAIL-ID_USER=support@example.com\nSMTP_EMAIL-ID_PASS=youcantguessthispassword\n```\n\n### Templates\nHere is the default template.\n\n![Screenshot](img.png)\n\nYou can override this template on any form by using the `Template` field. You can use Go 1.16 \u003e= embed package to separate your template files from your function file.\n```go\ncontact.AddEmail(formailer.Email{\n\t...\n\tTemplate: defaultTemplate,\n}\n\n//go:embed mytemplate.html\nvar defaultTemplate string\n\n// OR\n\ndefaultTemplate := `\n\u003chtml\u003e\n\u003chead\u003e\n    \u003cstyle\u003e\n        h3 {\n            color: #000;\n            margin-bottom: 5px;\n        }\n\n        p {\n            color: #333;\n            margin-bottom: 2rem;\n        }\n    \u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    {{ range $name, $value := .Values }}\n    \u003ch3\u003e{{$name}}\u003c/h3\u003e\n    \u003cp\u003e{{$value}}\u003c/p\u003e\n    {{ end }}\n\u003c/body\u003e\n\u003c/html\u003e\n`\n```\n\n### Custom Handlers\nFormailer ships with Netlify and Vercel handlers but if you need more control over the data. Or would like to run on a different platform, it's not too difficult to get setup. Here is a template to get you started.\n```go\nfunc Handler(w http.ResponseWriter, r *http.Request) {\n\t// pre-processing, check HTTP method\n\n\t// convert body from io.Reader to string\n\tbody := new(strings.Builder)\n\t_, err := io.Copy(body, r.Body)\n\tif err != nil {\n\t\t// handle error\n\t\treturn\n\t}\n\t\n\t// Parse body\n\tsubmission, err := formailer.Parse(r.Header.Get(\"Content-Type\"), body.String())\n\tif err != nil {\n\t\t// handle error\n\t\treturn\n\t}\n\n\t// manipulate data, check honey pot fields\n\t// handlers.VerifyRecaptcha()\n\n\t// Send emails\n\terr = submission.Send()\n\tif err != nil {\n\t\t// handle error\n\t\treturn\n\t}\n\n\t// handle success\n}\n```\n\n## Why did I buid Formailer?\n\nI love Jamstack but SaaS can get expensive pretty quickly. Netlify has a built in form system that costs $19/month after the first 100 submissions. It also has a serverless function system that allows for 125k invocations a month. So I did the obvious thing, create a library that handles forms for Jamstack sites.\n\n### The challenge\nNetlify barely supports Go, you can't even use the Netlify CLI to test Go functions. Every change had to be commited and tested directly on Netlify. Even worse is that I had minimal experience working with multipart forms before this project. And my testing software [Hoppscotch](https://hoppscotch.io) doesn't implement multipart forms in a traditional way which led to a bunch of builds that I thought didn't work but actually did.\n\nThere's also an annoying bug with environment variables where [functions can't read variabes defined in the `netlify.toml`](https://github.com/netlify/netlify-lambda/issues/59). So you'll just have to add them all in the Netlify UI.\n\nLater I switched to Vercel for testing which was a huge breath of fresh air. You can test Go functions locally even though Go support is still in alpha.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftorrayne%2Fformailer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftorrayne%2Fformailer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftorrayne%2Fformailer/lists"}