{"id":21997354,"url":"https://github.com/stephane-klein/gibbon-mail","last_synced_at":"2026-05-09T07:02:15.145Z","repository":{"id":232527793,"uuid":"199331252","full_name":"stephane-klein/gibbon-mail","owner":"stephane-klein","description":"Send mails with mjml Template and JSON Schema","archived":false,"fork":false,"pushed_at":"2023-04-20T21:58:59.000Z","size":1227,"stargazers_count":1,"open_issues_count":31,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-30T17:48:21.738Z","etag":null,"topics":["api","emails","form","json-schema","mjml","templates","transactional-emails"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stephane-klein.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2019-07-28T19:56:50.000Z","updated_at":"2023-04-05T08:14:35.000Z","dependencies_parsed_at":"2024-04-10T06:02:21.817Z","dependency_job_id":null,"html_url":"https://github.com/stephane-klein/gibbon-mail","commit_stats":null,"previous_names":["stephane-klein/gibbon-mail"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/stephane-klein/gibbon-mail","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephane-klein%2Fgibbon-mail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephane-klein%2Fgibbon-mail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephane-klein%2Fgibbon-mail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephane-klein%2Fgibbon-mail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stephane-klein","download_url":"https://codeload.github.com/stephane-klein/gibbon-mail/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephane-klein%2Fgibbon-mail/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32810381,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"online","status_checked_at":"2026-05-09T02:00:06.633Z","response_time":123,"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":["api","emails","form","json-schema","mjml","templates","transactional-emails"],"created_at":"2024-11-29T22:15:59.747Z","updated_at":"2026-05-09T07:02:15.112Z","avatar_url":"https://github.com/stephane-klein.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/spacefill/gibbon-mail/actions/workflows/main.yml/badge.svg)](https://github.com/spacefill/gibbon-mail/actions/workflows/main.yml)\n\n# Gibbon-mail\n\nDocker image: https://hub.docker.com/r/spacefill/gibbon-mail\n\nSend mails with mjml Template  and JSON Schema.\n\n- Project status: [POC](https://en.wikipedia.org/wiki/Proof_of_concept)\n- Screencast: https://youtu.be/9oih7cZTjk4\n- Docker Image: https://hub.docker.com/r/stephaneklein/gibbon-mail (Automated Builds configured on `master` branch)\n\nTo generate PDF instead send mails, see this project: [gibbon-pdf](https://github.com/stephane-klein/gibbon-pdf)\n\n## Why this project?\n\n- I would like to move transactionnal mail engine from my application in a separate service\n- I would like to allow humans to send email manually, via a simple application plugged to the same API.\n- I would like to keep a history (optionally) of all mail sent\n\nSee also Gibbon-mail alternative project: [Catapulte](https://github.com/jdrouet/catapulte) (Rust implementation of catapulte email sender).\n\n## Features\n\n- Send email from:\n  - Json field values (validated by [JSON Schema](https://json-schema.org/))\n  - [MJML](https://github.com/mjmlio/mjml) template file\n  - TXT template file\n  - Oneline Subject template file\n- Rest API endpoints to generate mail preview or send email\n- Web UI to generate email manually:\n  - HTML form are autogenerated by [JSON Schema](https://json-schema.org/)\n  - User can preview the email or send email\n- Optionnaly record all email sent\n- [cid](https://nodemailer.com/message/embedded-images/) image attachment support\n\n## Requirements\n\n- [direnv](https://direnv.net/)\n- [docker](https://www.docker.com/)\n- [nodejs](https://nodejs.org/en/)\n- [yarn](https://yarnpkg.com/)\n\nAll versions are specified in [.tool-versions](.tool-versions).\n\n### Installation\n\nYou can use [`asdf`](https://github.com/asdf-vm/asdf) to install dependencies:\n\n```sh\n$ asdf plugin-add direnv\n$ asdf plugin add nodejs\n$ asdf plugin add yarn\n$ asdf install\n$ direnv allow\n```\n\n## Roadmaps\n\n- [x] Integrate [`mozilla-services/react-jsonschema-form`](https://github.com/mozilla-services/react-jsonschema-form)\n- [x] Integrate [`mjmlio/mjml`](https://github.com/mjmlio/mjml)\n- [x] Send mails with [nodemailer](https://nodemailer.com)\n- [x] Add [mailhog](https://github.com/mailhog/MailHog) to test\n- [x] Docker Image (`stephaneklein/gibbon-mail:latest`)\n- [x] curl example\n- [x] Screencast\n- [x] Swagger\n- [x] Multi language mail template support #8\n- [x] Add [UISchema](https://react-jsonschema-form.readthedocs.io/en/latest/) support\n- [x] Check json input with JSON Schema\n- [ ] Test frontend\n- [X] Configure CI\n- [X] Add [Sentry](https://sentry.io/)\n- [ ] Add option to save mail sent (in PostgreSQL)\n\n[See other issues...](https://github.com/stephane-klein/gibbon-mail/issues)\n\n## This project is based on this stack\n\n- [Backend](backend/):\n  - [NodeJS](https://nodejs.org/en/) with [Koa](https://koajs.com/)\n  - [`mjmlio/mjml`](https://github.com/mjmlio/mjml) to generate Html email\n  - [Nunjucks](https://mozilla.github.io/nunjucks/) to fill Email templates\n  - [nodemailer](https://nodemailer.com) to send email\n  - [Swagger](https://swagger.io/tools/swagger-ui/) (see [swagger.yaml](backend/src/swagger.yaml) file)\n- [Frontend](frontend/)\n  - [ReactJS](https://en.reactjs.org/), [Axios](https://github.com/axios/axios), [React-router](https://github.com/ReactTraining/react-router)\n  - [react-jsonschema-form](https://github.com/mozilla-services/react-jsonschema-form) to generate Form from JSON Schema (need Bootstrap version `v3.3.6`)\n  - [Bootstrap](https://getbootstrap.com/)\n- Tooling\n  - [Jest](https://jestjs.io/) and [supertest](https://github.com/visionmedia/supertest) for backend tests\n  - [ESLint](https://eslint.org/)\n\n## Quick start\n\nYou can use gibbon-mail as a standalone app:\n\n```sh\n$ npm install -g @spacefill/gibbon-mail\n$ gibbon-mail\n```\n\nor as library:\n\n```js\nconst { createApp } = require('@spacefill/gibbon-mail')\n\nconst app = createApp()\n\nconst server = app.listen(\n  5000,\n  '0.0.0.0',\n  () =\u003e {\n    console.log(`Server listening on port: 5000`);\n  }\n);\n```\n\nIt's also available as [`docker-image`](docker-image/).\n\n## Docker Image\n\n[`spacefill/gibbon-mail`](https://hub.docker.com/r/spacefill/gibbon-mail) Docker\nImage is automatically builded with with our CI. We currently maintain several versions\nas we use [`semver`](https://semver.org/) to tag our docker images\n\n- `latest` tag is pushed with the last commit on `master`\n- `vX.X.X` tag are pushed when we push a new tag\n\nTo see how to create a new tag see [\"How to publish a new version\"](/README.md#how-to-publish-a-new-version)\n\n## Contribution\n\nIf you want to contribute see those READMEs:\n\n- [`backend/`](backend/)\n- [`frontend/`](frontend/)\n\n## How to publish a new github version\n\n- Every commit on `master` is release on `latest`.\n- Every [`tag`](https://github.com/spacefill/gibbon-mail/tags) is release with\n  the according version.\n\n### How to publish a tag\n\n1. Bump version\n\n```\n$ ./scripts/bump-project-to-version.sh 1.0.0\n```\n\nThis will automatically update version in `package.json` for frontend and backend.\n\n2. Create a PR to release with the bumped version\n3. When your PR is merged on master create and push tag\n\n```\n$ ./scripts/create-and-push-tag.sh\n```\n\nThis will automatically create a new local tag and push it.\n\n## FAQ\n\n### How can I enable Authentication system?\n\nThis project hasn't build-in authentication system, it's a internal service in your stack,\nyou must protect it by a private network or [Basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) system.\n\n### How does the multi-language support works?\n\n#### Language files\n\nInside your mail templates folders, you can create multiple languages files for each email, in the following format: `/mail-templates/email-folder/{lang}.(mjml|subject|txt)`.\n\nFor example, an email that supports French and English, and defaults to english, will have the following files in its template folder:\n\n```sh\n$ ls mail-templates/email-example\ndefault.mjml -\u003e en.mjml                 fr.mjml              en.mjml\ndefault.subject -\u003e en.subject           fr.subject           en.subject\ndefault.txt -\u003e en.mjml                  fr.txt               en.txt\n```\n\nNote: default files are actually symbolic links\n\n#### Telling Gibbon which language to use\n\nWhen using Gibbon to send an email, if the `lang` property is present in the body of the request, Gibbon will use the corresponding language files accordingly. If the language files are not found, Gibbon will use the default files\n\nFor example, the following request body will try to send a german email, or fallback to the default email if there are no german files in the template folder:\n\n```\n{\n  \"from\": \"no-reply@example.com\",\n  \"to\": \"john.doe@example.com\",\n  \"lang\": \"de\"\n}\n```\n\n#### Examples\n\n- Adding a french-only email\n  - create `/email-folder/FR.{txt,mjml,subject}` files\n  - run the following command to use French as the default language: `ln -s FR.subject default.subject ; ln -s FR.txt default.txt ; ln -s FR.mjml default.mjml`\n\n- Create an english version\n  - create `/email-folder/EN.{txt,mjml,subject}` files\n\n- Switch the default version from French to English\n  - `rm -f default.*`\n  - `ln -s EN.subject default.subject ; ln -s EN.txt default.txt ; ln -s EN.mjml default.mjml`\n\nIf the `lang` property is missing from the body of the request, Gibbon will fallback to the default version, and use the default files.\n\n\n### Why « Gibbon-mail » name?\n\n[Gibbon](https://en.wikipedia.org/wiki/Gibbon) as an allusion to [Mandrill App](https://mandrill.com/).\n\n### Custom nunjunks\n\nTo custom `nunjunks` you **must** use `gibbon-mail` as javascript library. You can't do it if you're using the docker version.\n\nYou can retrieve [`nunjuncks environment`](https://mozilla.github.io/nunjucks/fr/api.html#environment):\n\n```js\nconst { nunjucksEnv } = require('@spacefill/gibbon-mail')\n```\n\nYou can create a custom filter and add it to gibbon-mail:\n\n```js\nconst { createApp, nunjucksEnv } = require('@spacefill/gibbon-mail')\n\nfunction trimFilter(input, length) {\n    return String(input).slice(0, length);\n}\n\nnunjucksEnv.addFilter('trim', trimFilter);\n```\n\n### How can I keep an archive of all mails send by Gibbon-mail?\n\nConfigure `BCC` variable env as below example to send all mails send by Gibbon-mail to `log@example.com` email account.\n\n```\n# docker-compose.yml\nversion: \"3.7\"\nservices:\n  gibbon-mail:\n    image: stephaneklein/gibbon-mail:latest\n    ports:\n     - 5000:5000\n    volumes:\n     - ../mail-templates/:/templates/\n    environment:\n      SMTP_USERNAME: user\n      SMTP_PASSWORD: password\n      SMTP_HOST: mailcatcher\n      SMTP_PORT: 1025\n      BCC: log@example.com,test1@example.com\n```\n\nOr you can pass it to the body of the request as `bcc`.\n\n### Why can I configure two smtp service?\n\nGibbon-mail support two smtp server configuration, for instance:\n\n```\n# docker-compose.yml\nversion: \"3.7\"\nservices:\n  gibbon-mail:\n    image: stephaneklein/gibbon-mail:latest\n    ports:\n     - 5000:5000\n    volumes:\n     - ../mail-templates/:/templates/\n    environment:\n      SMTP_USERNAME: user\n      SMTP_PASSWORD: password\n      SMTP_HOST: mailcatcher\n      SMTP_PORT: 1025\n      SMTP_LABEL: \"Send mail to Mailcatcher\"\n      SMTP2_USERNAME: user\n      SMTP2_PASSWORD: password\n      SMTP2_HOST: example.com\n      SMTP2_PORT: 25\n      SMTP2_LABEL: \"Send mail with example.com smtp server\"\n      BCC: log@example.com\n```\n\nYou can use `SMTP2_URL` for instance on staging environment: by default, you send mail to Mailhog fake smtp server et optionnaly on real smtp server to test your mail template rendering on several email clients.\n\n---\n\nEmails examples:\n\n- [Sentry](https://github.com/getsentry/sentry/tree/master/src/sentry/templates/sentry/emails)\n- [GitLab](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/views/notify)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephane-klein%2Fgibbon-mail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstephane-klein%2Fgibbon-mail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephane-klein%2Fgibbon-mail/lists"}