@technomoron/mail-magic 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.do-realease.sh +10 -0
- package/.editorconfig +9 -0
- package/.env-dist +62 -0
- package/.prettierrc +14 -0
- package/.vscode/extensions.json +15 -0
- package/.vscode/settings.json +123 -0
- package/CHANGES +25 -0
- package/README.md +63 -0
- package/config-example/form-template/default.njk +102 -0
- package/config-example/forms.config.json +8 -0
- package/config-example/init-data.json +33 -0
- package/config-example/tx-template/default.njk +107 -0
- package/dist/api/forms.js +175 -0
- package/dist/api/mailer.js +213 -0
- package/dist/index.js +50 -0
- package/dist/models/db.js +99 -0
- package/dist/models/domain.js +58 -0
- package/dist/models/form.js +168 -0
- package/dist/models/init.js +176 -0
- package/dist/models/txmail.js +167 -0
- package/dist/models/user.js +65 -0
- package/dist/server.js +22 -0
- package/dist/store/envloader.js +116 -0
- package/dist/store/store.js +85 -0
- package/dist/types.js +1 -0
- package/dist/util.js +94 -0
- package/ecosystem.config.cjs +42 -0
- package/eslint.config.mjs +104 -0
- package/package.json +67 -0
- package/src/api/forms.ts +209 -0
- package/src/api/mailer.ts +242 -0
- package/src/index.ts +67 -0
- package/src/models/db.ts +112 -0
- package/src/models/domain.ts +72 -0
- package/src/models/form.ts +198 -0
- package/src/models/init.ts +237 -0
- package/src/models/txmail.ts +199 -0
- package/src/models/user.ts +79 -0
- package/src/server.ts +27 -0
- package/src/store/envloader.ts +117 -0
- package/src/store/store.ts +116 -0
- package/src/types.ts +39 -0
- package/src/util.ts +111 -0
- package/test1.sh +13 -0
- package/tsconfig.json +14 -0
package/.do-realease.sh
ADDED
package/.editorconfig
ADDED
package/.env-dist
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Specifies the environment in which the app is running Possible values: development, production, staging
|
|
2
|
+
NODE_ENV=development
|
|
3
|
+
|
|
4
|
+
# Defines the port on which the app listens. Default 3780 [number]
|
|
5
|
+
API_PORT=3776
|
|
6
|
+
|
|
7
|
+
# Sets the local IP address for the API to listen at
|
|
8
|
+
API_HOST=0.0.0.0
|
|
9
|
+
|
|
10
|
+
# Reload init-data.db automatically on change [boolean]
|
|
11
|
+
DB_AUTO_RELOAD=true
|
|
12
|
+
|
|
13
|
+
# Whether to force sync on table definitions (ALTER TABLE) [boolean]
|
|
14
|
+
DB_FORCE_SYNC=false
|
|
15
|
+
|
|
16
|
+
# Sets the public URL for the API (i.e. https://ml.example.com:3790)
|
|
17
|
+
API_URL=http://localhost:3776
|
|
18
|
+
|
|
19
|
+
# Path to directory where config files are located
|
|
20
|
+
CONFIG_PATH=./config/
|
|
21
|
+
|
|
22
|
+
# Database username for API database
|
|
23
|
+
DB_USER=
|
|
24
|
+
|
|
25
|
+
# Password for API database
|
|
26
|
+
DB_PASS=
|
|
27
|
+
|
|
28
|
+
# Name of API database. Filename for sqlite3, database name for others
|
|
29
|
+
DB_NAME=maildata
|
|
30
|
+
|
|
31
|
+
# Host of API database
|
|
32
|
+
DB_HOST=localhost
|
|
33
|
+
|
|
34
|
+
# Database type of WP database Possible values: sqlite
|
|
35
|
+
DB_TYPE=sqlite
|
|
36
|
+
|
|
37
|
+
# Log SQL statements [boolean]
|
|
38
|
+
DB_LOG=false
|
|
39
|
+
|
|
40
|
+
# Enable debug output, including nodemailer and API [boolean]
|
|
41
|
+
DEBUG=false
|
|
42
|
+
|
|
43
|
+
# Hostname of SMTP sending host
|
|
44
|
+
SMTP_HOST=localhost
|
|
45
|
+
|
|
46
|
+
# SMTP host server port [number]
|
|
47
|
+
SMTP_PORT=587
|
|
48
|
+
|
|
49
|
+
# Use secure connection to SMTP host (SSL/TSL) [boolean]
|
|
50
|
+
SMTP_SECURE=false
|
|
51
|
+
|
|
52
|
+
# Reject bad cert/TLS connection to SMTP host [boolean]
|
|
53
|
+
SMTP_TLS_REJECT=false
|
|
54
|
+
|
|
55
|
+
# Username for SMTP host
|
|
56
|
+
SMTP_USER=
|
|
57
|
+
|
|
58
|
+
# Password for SMTP host
|
|
59
|
+
SMTP_PASSWORD=
|
|
60
|
+
|
|
61
|
+
# Path for attached files
|
|
62
|
+
UPLOAD_PATH=./uploads/
|
package/.prettierrc
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tabWidth": 4,
|
|
3
|
+
"useTabs": true,
|
|
4
|
+
"singleQuote": true,
|
|
5
|
+
"semi": true,
|
|
6
|
+
"trailingComma": "none",
|
|
7
|
+
"bracketSpacing": true,
|
|
8
|
+
"bracketSameLine": true,
|
|
9
|
+
"arrowParens": "always",
|
|
10
|
+
"printWidth": 120,
|
|
11
|
+
"vueIndentScriptAndStyle": false,
|
|
12
|
+
"htmlWhitespaceSensitivity": "ignore",
|
|
13
|
+
"singleAttributePerLine": false
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"recommendations": [
|
|
3
|
+
"dbaeumer.vscode-eslint",
|
|
4
|
+
"esbenp.prettier-vscode",
|
|
5
|
+
"editorconfig.editorconfig",
|
|
6
|
+
"Vue.volar",
|
|
7
|
+
"wayou.vscode-todo-highlight"
|
|
8
|
+
],
|
|
9
|
+
"unwantedRecommendations": [
|
|
10
|
+
"octref.vetur",
|
|
11
|
+
"hookyqr.beautify",
|
|
12
|
+
"dbaeumer.jshint",
|
|
13
|
+
"ms-vscode.vscode-typescript-tslint-plugin"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
{
|
|
2
|
+
"editor.detectIndentation": false,
|
|
3
|
+
"editor.insertSpaces": false,
|
|
4
|
+
"editor.tabSize": 4,
|
|
5
|
+
"editor.bracketPairColorization.enabled": true,
|
|
6
|
+
"editor.guides.bracketPairs": true,
|
|
7
|
+
"editor.formatOnSave": true,
|
|
8
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
9
|
+
"editor.codeActionsOnSave": {
|
|
10
|
+
"source.fixAll": "always",
|
|
11
|
+
"source.fixAll.eslint": "always"
|
|
12
|
+
},
|
|
13
|
+
"[json]": {
|
|
14
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
15
|
+
},
|
|
16
|
+
"[jsonc]": {
|
|
17
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
18
|
+
},
|
|
19
|
+
"eslint.alwaysShowStatus": true,
|
|
20
|
+
"prettier.enable": true,
|
|
21
|
+
"typescript.tsdk": "node_modules/typescript/lib",
|
|
22
|
+
"eslint.run": "onSave",
|
|
23
|
+
"eslint.format.enable": true,
|
|
24
|
+
"editor.formatOnType": true,
|
|
25
|
+
"eslint.useFlatConfig": true,
|
|
26
|
+
"eslint.probe": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue"],
|
|
27
|
+
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue"],
|
|
28
|
+
"explorer.fileNesting.enabled": true,
|
|
29
|
+
"explorer.fileNesting.expand": false,
|
|
30
|
+
"explorer.fileNesting.patterns": {
|
|
31
|
+
".clang-tidy": ".clang-format, .clangd, compile_commands.json",
|
|
32
|
+
".env": "*.env, .env.*, .envrc, env.d.ts",
|
|
33
|
+
".gitignore": ".gitattributes, .gitmodules, .gitmessage, .lfsconfig, .mailmap, .git-blame*",
|
|
34
|
+
".project": ".classpath",
|
|
35
|
+
"+layout.svelte": "+layout.ts,+layout.ts,+layout.js,+layout.server.ts,+layout.server.js,+layout.gql",
|
|
36
|
+
"+page.svelte": "+page.server.ts,+page.server.js,+page.ts,+page.js,+page.gql",
|
|
37
|
+
"ansible.cfg": "ansible.cfg, .ansible-lint, requirements.yml",
|
|
38
|
+
"app.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
39
|
+
"application.properties": "*.properties",
|
|
40
|
+
"artisan": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, rspack.config.*, server.php, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, webpack.mix.js, windi.config.*",
|
|
41
|
+
"astro.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
42
|
+
"build-wrapper.log": "build-wrapper*.log, build-wrapper-dump*.json, build-wrapper-win*.exe, build-wrapper-linux*, build-wrapper-macosx*",
|
|
43
|
+
"BUILD.bazel": "*.bzl, *.bazel, *.bazelrc, bazel.rc, .bazelignore, .bazelproject, .bazelversion, MODULE.bazel.lock, WORKSPACE",
|
|
44
|
+
"Cargo.toml": ".clippy.toml, .rustfmt.toml, Cargo.Bazel.lock, Cargo.lock, clippy.toml, cross.toml, insta.yaml, rust-toolchain.toml, rustfmt.toml",
|
|
45
|
+
"CMakeLists.txt": "*.cmake, *.cmake.in, .cmake-format.yaml, CMakePresets.json, CMakeCache.txt",
|
|
46
|
+
"composer.json": ".php*.cache, composer.lock, phpunit.xml*, psalm*.xml",
|
|
47
|
+
"default.nix": "shell.nix",
|
|
48
|
+
"deno.json*": "*.env, .env.*, .envrc, api-extractor.json, deno.lock, env.d.ts, import-map.json, import_map.json, jsconfig.*, tsconfig.*, tsdoc.*",
|
|
49
|
+
"Dockerfile": "*.dockerfile, .devcontainer.*, .dockerignore, captain-definition, compose.*, docker-compose.*, dockerfile*",
|
|
50
|
+
"flake.nix": "flake.lock",
|
|
51
|
+
"gatsby-config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, gatsby-browser.*, gatsby-node.*, gatsby-ssr.*, gatsby-transformer.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
52
|
+
"gemfile": ".ruby-version, gemfile.lock",
|
|
53
|
+
"go.mod": ".air*, go.sum",
|
|
54
|
+
"go.work": "go.work.sum",
|
|
55
|
+
"hatch.toml": ".editorconfig, .flake8, .isort.cfg, .python-version, hatch.toml, requirements*.in, requirements*.pip, requirements*.txt, tox.ini",
|
|
56
|
+
"I*.cs": "$(capture).cs",
|
|
57
|
+
"Makefile": "*.mk",
|
|
58
|
+
"mix.exs": ".credo.exs, .dialyzer_ignore.exs, .formatter.exs, .iex.exs, .tool-versions, mix.lock",
|
|
59
|
+
"next.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, next-env.d.ts, next-i18next.config.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
60
|
+
"nuxt.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .nuxtignore, .nuxtrc, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
61
|
+
"package.json": "*.code-workspace, .browserslist*, .circleci*, .commitlint*, .cspell*, .cursor*, .cz-config.js, .czrc, .dlint.json, .dprint.json*, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitmojirc.json, .gitpod*, .huskyrc*, .jslint*, .knip.*, .lintstagedrc*, .ls-lint.yml, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .pylintrc, .release-please*.json, .releaserc*, .ruff.toml, .sentry*, .shellcheckrc, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .windsurfrules, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, biome.json*, bower.json, build.config.*, bun.lock, bun.lockb, bunfig.toml, colada.options.ts, commitlint*, crowdin*, cspell*, dangerfile*, dlint.json, dprint.json*, ec.config.*, electron-builder.*, eslint*, firebase.json, grunt*, gulp*, jenkins*, knip.*, lerna*, lint-staged*, nest-cli.*, netlify*, nixpacks*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-please*.json, release-tasks.sh, release.config.*, renovate*, rolldown.config.*, rollup.config.*, rspack*, ruff.toml, sentry.*.config.ts, simple-git-hooks*, sonar-project.properties, stylelint*, tsdown.config.*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, wrangler.*, xo.config.*, yarn*",
|
|
62
|
+
"Pipfile": ".editorconfig, .flake8, .isort.cfg, .python-version, Pipfile, Pipfile.lock, requirements*.in, requirements*.pip, requirements*.txt, tox.ini",
|
|
63
|
+
"pom.xml": "mvnw*",
|
|
64
|
+
"pubspec.yaml": ".metadata, .packages, all_lint_rules.yaml, analysis_options.yaml, build.yaml, pubspec.lock, pubspec_overrides.yaml",
|
|
65
|
+
"pyproject.toml": ".commitlint*, .cspell*, .dlint.json, .dprint.json*, .editorconfig, .eslint*, .flake8, .flowconfig, .isort.cfg, .jslint*, .lintstagedrc*, .ls-lint.yml, .markdownlint*, .pdm-python, .pdm.toml, .prettier*, .pylintrc, .python-version, .ruff.toml, .shellcheckrc, .stylelint*, .textlint*, .xo-config*, .yamllint*, MANIFEST.in, Pipfile, Pipfile.lock, biome.json*, commitlint*, cspell*, dangerfile*, dlint.json, dprint.json*, eslint*, hatch.toml, lint-staged*, pdm.lock, phpcs.xml, poetry.lock, poetry.toml, prettier*, pyproject.toml, pyrightconfig.json, requirements*.in, requirements*.pip, requirements*.txt, ruff.toml, setup.cfg, setup.py, stylelint*, tox.ini, tslint*, uv.lock, uv.toml, xo.config.*",
|
|
66
|
+
"quasar.conf.js": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, quasar.extensions.json, react-router.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
67
|
+
"readme*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
|
|
68
|
+
"Readme*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
|
|
69
|
+
"README*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
|
|
70
|
+
"remix.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, remix.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
71
|
+
"requirements.txt": ".editorconfig, .flake8, .isort.cfg, .python-version, requirements*.in, requirements*.pip, requirements*.txt, tox.ini",
|
|
72
|
+
"rush.json": "*.code-workspace, .browserslist*, .circleci*, .commitlint*, .cspell*, .cursor*, .cz-config.js, .czrc, .dlint.json, .dprint.json*, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitmojirc.json, .gitpod*, .huskyrc*, .jslint*, .knip.*, .lintstagedrc*, .ls-lint.yml, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .pylintrc, .release-please*.json, .releaserc*, .ruff.toml, .sentry*, .shellcheckrc, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .windsurfrules, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, biome.json*, bower.json, build.config.*, bun.lock, bun.lockb, bunfig.toml, colada.options.ts, commitlint*, crowdin*, cspell*, dangerfile*, dlint.json, dprint.json*, ec.config.*, electron-builder.*, eslint*, firebase.json, grunt*, gulp*, jenkins*, knip.*, lerna*, lint-staged*, nest-cli.*, netlify*, nixpacks*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-please*.json, release-tasks.sh, release.config.*, renovate*, rolldown.config.*, rollup.config.*, rspack*, ruff.toml, sentry.*.config.ts, simple-git-hooks*, sonar-project.properties, stylelint*, tsdown.config.*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, wrangler.*, xo.config.*, yarn*",
|
|
73
|
+
"sanity.config.*": "sanity.cli.*, sanity.types.ts, schema.json",
|
|
74
|
+
"setup.cfg": ".editorconfig, .flake8, .isort.cfg, .python-version, MANIFEST.in, requirements*.in, requirements*.pip, requirements*.txt, setup.cfg, tox.ini",
|
|
75
|
+
"setup.py": ".editorconfig, .flake8, .isort.cfg, .python-version, MANIFEST.in, requirements*.in, requirements*.pip, requirements*.txt, setup.cfg, setup.py, tox.ini",
|
|
76
|
+
"shims.d.ts": "*.d.ts",
|
|
77
|
+
"svelte.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, houdini.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, mdsvex.config.js, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vite.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
78
|
+
"vite.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
79
|
+
"vue.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, content.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, react-router.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
|
|
80
|
+
"*.asax": "$(capture).*.cs, $(capture).*.vb",
|
|
81
|
+
"*.ascx": "$(capture).*.cs, $(capture).*.vb",
|
|
82
|
+
"*.ashx": "$(capture).*.cs, $(capture).*.vb",
|
|
83
|
+
"*.aspx": "$(capture).*.cs, $(capture).*.vb",
|
|
84
|
+
"*.axaml": "$(capture).axaml.cs",
|
|
85
|
+
"*.bloc.dart": "$(capture).event.dart, $(capture).state.dart",
|
|
86
|
+
"*.c": "$(capture).h",
|
|
87
|
+
"*.cc": "$(capture).hpp, $(capture).h, $(capture).hxx, $(capture).hh",
|
|
88
|
+
"*.cjs": "$(capture).cjs.map, $(capture).*.cjs, $(capture)_*.cjs",
|
|
89
|
+
"*.component.ts": "$(capture).component.html, $(capture).component.spec.ts, $(capture).component.css, $(capture).component.scss, $(capture).component.sass, $(capture).component.less",
|
|
90
|
+
"*.cpp": "$(capture).hpp, $(capture).h, $(capture).hxx, $(capture).hh",
|
|
91
|
+
"*.cs": "$(capture).*.cs",
|
|
92
|
+
"*.cshtml": "$(capture).cshtml.cs, $(capture).cshtml.css",
|
|
93
|
+
"*.csproj": "*.config, *proj.user, appsettings.*, bundleconfig.json",
|
|
94
|
+
"*.css": "$(capture).css.map, $(capture).*.css",
|
|
95
|
+
"*.cxx": "$(capture).hpp, $(capture).h, $(capture).hxx, $(capture).hh",
|
|
96
|
+
"*.dart": "$(capture).freezed.dart, $(capture).g.dart",
|
|
97
|
+
"*.db": "*.db-shm, *.db-wal",
|
|
98
|
+
"*.ex": "$(capture).html.eex, $(capture).html.heex, $(capture).html.leex",
|
|
99
|
+
"*.fs": "$(capture).fs.js, $(capture).fs.js.map, $(capture).fs.jsx, $(capture).fs.ts, $(capture).fs.tsx, $(capture).fs.rs, $(capture).fs.php, $(capture).fs.dart",
|
|
100
|
+
"*.go": "$(capture)_test.go",
|
|
101
|
+
"*.java": "$(capture).class",
|
|
102
|
+
"*.js": "$(capture).js.map, $(capture).*.js, $(capture)_*.js, $(capture).d.ts, $(capture).d.ts.map, $(capture).js.flow",
|
|
103
|
+
"*.jsx": "$(capture).js, $(capture).*.jsx, $(capture)_*.js, $(capture)_*.jsx, $(capture).css, $(capture).module.css, $(capture).less, $(capture).module.less, $(capture).module.less.d.ts, $(capture).scss, $(capture).module.scss, $(capture).module.scss.d.ts",
|
|
104
|
+
"*.master": "$(capture).*.cs, $(capture).*.vb",
|
|
105
|
+
"*.md": "$(capture).*",
|
|
106
|
+
"*.mjs": "$(capture).mjs.map, $(capture).*.mjs, $(capture)_*.mjs",
|
|
107
|
+
"*.module.ts": "$(capture).resolver.ts, $(capture).controller.ts, $(capture).service.ts",
|
|
108
|
+
"*.mts": "$(capture).mts.map, $(capture).*.mts, $(capture)_*.mts",
|
|
109
|
+
"*.proto": "$(capture).pb.go, $(capture).pb.micro.go",
|
|
110
|
+
"*.pubxml": "$(capture).pubxml.user",
|
|
111
|
+
"*.py": "$(capture).pyi",
|
|
112
|
+
"*.razor": "$(capture).razor.cs, $(capture).razor.css, $(capture).razor.scss",
|
|
113
|
+
"*.resx": "$(capture).*.resx, $(capture).designer.cs, $(capture).designer.vb",
|
|
114
|
+
"*.tex": "$(capture).acn, $(capture).acr, $(capture).alg, $(capture).aux, $(capture).bbl, $(capture).bbl-SAVE-ERROR, $(capture).bcf, $(capture).blg, $(capture).fdb_latexmk, $(capture).fls, $(capture).glg, $(capture).glo, $(capture).gls, $(capture).idx, $(capture).ind, $(capture).ist, $(capture).lof, $(capture).log, $(capture).lot, $(capture).nav, $(capture).out, $(capture).run.xml, $(capture).snm, $(capture).synctex.gz, $(capture).toc, $(capture).xdv",
|
|
115
|
+
"*.ts": "$(capture).js, $(capture).d.ts.map, $(capture).*.ts, $(capture)_*.js, $(capture)_*.ts",
|
|
116
|
+
"*.tsx": "$(capture).ts, $(capture).*.tsx, $(capture)_*.ts, $(capture)_*.tsx, $(capture).css, $(capture).module.css, $(capture).less, $(capture).module.less, $(capture).module.less.d.ts, $(capture).scss, $(capture).module.scss, $(capture).module.scss.d.ts, $(capture).css.ts",
|
|
117
|
+
"*.vbproj": "*.config, *proj.user, appsettings.*, bundleconfig.json",
|
|
118
|
+
"*.vue": "$(capture).*.ts, $(capture).*.js, $(capture).story.vue",
|
|
119
|
+
"*.w": "$(capture).*.w, I$(capture).w",
|
|
120
|
+
"*.wat": "$(capture).wasm",
|
|
121
|
+
"*.xaml": "$(capture).xaml.cs"
|
|
122
|
+
}
|
|
123
|
+
}
|
package/CHANGES
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
CHANGES
|
|
2
|
+
|
|
3
|
+
Version 1.0.4 (2025-09-27)
|
|
4
|
+
|
|
5
|
+
- Surface request metadata (client IP, IP chain, received-at) to form and transactional
|
|
6
|
+
template rendering and update the bundled templates to display it.
|
|
7
|
+
- Correct domain lookups to match `api_domain.name` during form and mail submission
|
|
8
|
+
authentication so legitimate domains are accepted.
|
|
9
|
+
- Export `createMailMagicServer`/`startMailMagicServer` helpers and only auto-start when
|
|
10
|
+
executed directly, printing the bound host/port after.
|
|
11
|
+
|
|
12
|
+
Version 1.0.3 (2025-09-26)
|
|
13
|
+
|
|
14
|
+
- Introduced the transactional mail model and API route updates so stored templates,
|
|
15
|
+
attachments, and message delivery flow through `api_txmail` instead of the
|
|
16
|
+
removed `api_template`.
|
|
17
|
+
- Let authenticated clients upload form templates via the API, aligning filename/slug
|
|
18
|
+
generation with the new singular config structure.
|
|
19
|
+
- Replaced the Nunjucks loader with `@technomoron/unyuck` to flatten includes
|
|
20
|
+
and collect referenced assets before persisting them.
|
|
21
|
+
- Refreshed tooling and metadata (ESLint/Prettier configs, README, ecosystem config)
|
|
22
|
+
to match the renamed package and repository.
|
|
23
|
+
- Added workspace metadata and sample templates so pnpm and new installs pick up example
|
|
24
|
+
assets.
|
|
25
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @technomoron/mail-magic
|
|
2
|
+
|
|
3
|
+
Mail Magic is a TypeScript service for managing, templating, and delivering transactional emails. It exposes a small REST API built on `@technomoron/api-server-base`, persists data with Sequelize/SQLite, and renders outbound messages with Nunjucks templates.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Upload, store, and send templated email content through a JSON API
|
|
8
|
+
- Preprocess template assets with `@technomoron/unyuck` before persisting
|
|
9
|
+
- Nodemailer transport configuration driven by environment variables
|
|
10
|
+
- SQLite-backed data models for domains, users, forms, and templates
|
|
11
|
+
- Type-safe configuration loader powered by `@technomoron/env-loader`
|
|
12
|
+
|
|
13
|
+
## Getting Started
|
|
14
|
+
|
|
15
|
+
1. Clone the repository: `git clone git@github.com:technomoron/mail-magic.git`
|
|
16
|
+
2. Install dependencies: `npm install`
|
|
17
|
+
3. Create your environment file: copy `.env-dist` to `.env` and adjust values
|
|
18
|
+
4. Populate the config directory (see `config-example/` for a reference layout)
|
|
19
|
+
5. Build the project: `npm run build`
|
|
20
|
+
6. Start the API server: `npm run start`
|
|
21
|
+
|
|
22
|
+
During development you can run `npm run dev` for a watch mode that recompiles on change and restarts via `nodemon`.
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
- **Environment variables** are defined in `src/store/envloader.ts`. Important settings include SMTP credentials, API host/port, the config directory path, and database options.
|
|
27
|
+
- **Config directory** (`CONFIG_PATH`) contains JSON seed data (`init-data.json`), optional API key files, and template assets. Review `config-example/` for the recommended layout, in particular the `form-template/` and `tx-template/` folders used for compiled Nunjucks templates.
|
|
28
|
+
- **Database** defaults to SQLite (`maildata.db`). You can switch dialects by updating the environment options if your deployment requires another database.
|
|
29
|
+
|
|
30
|
+
When `DB_AUTO_RELOAD` is enabled the service watches `init-data.json` and refreshes templates and forms without a restart.
|
|
31
|
+
|
|
32
|
+
## API Overview
|
|
33
|
+
|
|
34
|
+
| Method | Path | Description |
|
|
35
|
+
| ------ | ------------------- | --------------------------------------------- |
|
|
36
|
+
| POST | `/v1/tx/template` | Store or update a transactional mail template |
|
|
37
|
+
| POST | `/v1/tx/message` | Render and send a stored transactional mail |
|
|
38
|
+
| POST | `/v1/form/template` | Store or update a form submission template |
|
|
39
|
+
| POST | `/v1/form/message` | Submit a form payload and deliver the email |
|
|
40
|
+
|
|
41
|
+
All authenticated routes expect an API token associated with a configured user. Attachments can be uploaded alongside the `/v1/tx/message` request and are forwarded by Nodemailer.
|
|
42
|
+
|
|
43
|
+
## Available Scripts
|
|
44
|
+
|
|
45
|
+
- `npm run dev` – Start the API server in watch mode
|
|
46
|
+
- `npm run build` – Compile TypeScript to the `dist/` directory
|
|
47
|
+
- `npm run start` – Launch the compiled server from `dist/`
|
|
48
|
+
- `npm run lint` – Lint the project with ESLint
|
|
49
|
+
- `npm run format` – Apply ESLint autofixes followed by Prettier formatting
|
|
50
|
+
- `npm run cleanbuild` – Clean, lint, format, and rebuild the project
|
|
51
|
+
|
|
52
|
+
## Repository & Support
|
|
53
|
+
|
|
54
|
+
- Repository: https://github.com/technomoron/mail-magic
|
|
55
|
+
- Issues: https://github.com/technomoron/mail-magic/issues
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
This project is released under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
60
|
+
|
|
61
|
+
## Copyright
|
|
62
|
+
|
|
63
|
+
Copyright (c) 2025 Bjørn Erik Jacobsen. All rights reserved.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<title>Form Submission Details</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: Arial, sans-serif;
|
|
10
|
+
line-height: 1.6;
|
|
11
|
+
color: #333;
|
|
12
|
+
}
|
|
13
|
+
h3 {
|
|
14
|
+
color: #444;
|
|
15
|
+
}
|
|
16
|
+
table {
|
|
17
|
+
width: 100%;
|
|
18
|
+
border-collapse: collapse;
|
|
19
|
+
margin-bottom: 20px;
|
|
20
|
+
}
|
|
21
|
+
th,
|
|
22
|
+
td {
|
|
23
|
+
border: 1px solid #ddd;
|
|
24
|
+
padding: 8px;
|
|
25
|
+
text-align: left;
|
|
26
|
+
}
|
|
27
|
+
th {
|
|
28
|
+
background-color: #f5f5f5;
|
|
29
|
+
}
|
|
30
|
+
</style>
|
|
31
|
+
</head>
|
|
32
|
+
<body>
|
|
33
|
+
<h3>Form Fields</h3>
|
|
34
|
+
{% if formFields %}
|
|
35
|
+
<table>
|
|
36
|
+
<thead>
|
|
37
|
+
<tr>
|
|
38
|
+
<th>Field</th>
|
|
39
|
+
<th>Value</th>
|
|
40
|
+
</tr>
|
|
41
|
+
</thead>
|
|
42
|
+
<tbody>
|
|
43
|
+
{% for field, value in formFields %}
|
|
44
|
+
<tr>
|
|
45
|
+
<td>{{ field }}</td>
|
|
46
|
+
<td>{{ value }}</td>
|
|
47
|
+
</tr>
|
|
48
|
+
{% endfor %}
|
|
49
|
+
</tbody>
|
|
50
|
+
</table>
|
|
51
|
+
{% else %}
|
|
52
|
+
<p>No form fields submitted.</p>
|
|
53
|
+
{% endif %}
|
|
54
|
+
|
|
55
|
+
<h3>File Metadata</h3>
|
|
56
|
+
{% if files and files.length %}
|
|
57
|
+
<table>
|
|
58
|
+
<thead>
|
|
59
|
+
<tr>
|
|
60
|
+
<th>Filename</th>
|
|
61
|
+
<th>Path</th>
|
|
62
|
+
</tr>
|
|
63
|
+
</thead>
|
|
64
|
+
<tbody>
|
|
65
|
+
{% for file in files %}
|
|
66
|
+
<tr>
|
|
67
|
+
<td>{{ file.originalname }}</td>
|
|
68
|
+
<td>{{ file.path }}</td>
|
|
69
|
+
</tr>
|
|
70
|
+
{% endfor %}
|
|
71
|
+
</tbody>
|
|
72
|
+
</table>
|
|
73
|
+
{% else %}
|
|
74
|
+
<p>No files attached.</p>
|
|
75
|
+
{% endif %}
|
|
76
|
+
|
|
77
|
+
<h3>Request Metadata</h3>
|
|
78
|
+
{% if _meta_ %}
|
|
79
|
+
<table>
|
|
80
|
+
<tbody>
|
|
81
|
+
<tr>
|
|
82
|
+
<th>Client IP</th>
|
|
83
|
+
<td>{{ _meta_.client_ip | default('Unknown') }}</td>
|
|
84
|
+
</tr>
|
|
85
|
+
<tr>
|
|
86
|
+
<th>Received At</th>
|
|
87
|
+
<td>{{ _meta_.received_at | default('Unknown') }}</td>
|
|
88
|
+
</tr>
|
|
89
|
+
{% if _meta_.ip_chain and _meta_.ip_chain.length %}
|
|
90
|
+
<tr>
|
|
91
|
+
<th>IP Chain</th>
|
|
92
|
+
<td>{{ _meta_.ip_chain | join(', ') }}</td>
|
|
93
|
+
</tr>
|
|
94
|
+
{% endif %}
|
|
95
|
+
</tbody>
|
|
96
|
+
</table>
|
|
97
|
+
{% else %}
|
|
98
|
+
<p>No metadata provided.</p>
|
|
99
|
+
{% endif %}
|
|
100
|
+
</body>
|
|
101
|
+
</html>
|
|
102
|
+
</html>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"user": [
|
|
3
|
+
{
|
|
4
|
+
"user_id": 1,
|
|
5
|
+
"idname": "testuser",
|
|
6
|
+
"token": "SomethingWeirdWhoKnows",
|
|
7
|
+
"name": "Test Inc.",
|
|
8
|
+
"email": "noreply@example.com"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"domain": [
|
|
12
|
+
{
|
|
13
|
+
"domain_id": 1,
|
|
14
|
+
"user_id": 1,
|
|
15
|
+
"domain": "mail.example.com",
|
|
16
|
+
"sender": "Some User <noreply@example.com>"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"template": [
|
|
20
|
+
{
|
|
21
|
+
"template_id": 1,
|
|
22
|
+
"user_id": 1,
|
|
23
|
+
"domain_id": 1,
|
|
24
|
+
"name": "test",
|
|
25
|
+
"locale": "",
|
|
26
|
+
"template": "",
|
|
27
|
+
"template_file": "",
|
|
28
|
+
"sender": "someone@mail.example.com",
|
|
29
|
+
"subject": "Example Mail",
|
|
30
|
+
"slug": "test"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>Email Details</title>
|
|
6
|
+
<style>
|
|
7
|
+
body {
|
|
8
|
+
font-family: Arial, sans-serif;
|
|
9
|
+
color: #333;
|
|
10
|
+
line-height: 1.6;
|
|
11
|
+
}
|
|
12
|
+
h2 {
|
|
13
|
+
margin-top: 30px;
|
|
14
|
+
border-bottom: 1px solid #ccc;
|
|
15
|
+
}
|
|
16
|
+
table {
|
|
17
|
+
width: 100%;
|
|
18
|
+
border-collapse: collapse;
|
|
19
|
+
margin-top: 10px;
|
|
20
|
+
}
|
|
21
|
+
th,
|
|
22
|
+
td {
|
|
23
|
+
padding: 8px;
|
|
24
|
+
border: 1px solid #ddd;
|
|
25
|
+
}
|
|
26
|
+
th {
|
|
27
|
+
background: #f0f0f0;
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
30
|
+
</head>
|
|
31
|
+
<body>
|
|
32
|
+
<h2>Email Recipient</h2>
|
|
33
|
+
<p>
|
|
34
|
+
<strong>To:</strong>
|
|
35
|
+
{{ _rcpt_email_ }}
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
<h2>Template Variables</h2>
|
|
39
|
+
|
|
40
|
+
{% if _vars_ %}
|
|
41
|
+
<table>
|
|
42
|
+
<thead>
|
|
43
|
+
<tr>
|
|
44
|
+
<th>Key</th>
|
|
45
|
+
<th>Value</th>
|
|
46
|
+
</tr>
|
|
47
|
+
</thead>
|
|
48
|
+
<tbody>
|
|
49
|
+
{% for key, value in _vars_ %}
|
|
50
|
+
<tr>
|
|
51
|
+
<td>{{ key }}</td>
|
|
52
|
+
<td>{{ value }}</td>
|
|
53
|
+
</tr>
|
|
54
|
+
{% endfor %}
|
|
55
|
+
</tbody>
|
|
56
|
+
</table>
|
|
57
|
+
{% else %}
|
|
58
|
+
<p>No variables found.</p>
|
|
59
|
+
{% endif %}
|
|
60
|
+
|
|
61
|
+
<h2>Attachments</h2>
|
|
62
|
+
{% if _attachments_ and _attachments_ | length > 0 %}
|
|
63
|
+
<table>
|
|
64
|
+
<thead>
|
|
65
|
+
<tr>
|
|
66
|
+
<th>Label</th>
|
|
67
|
+
<th>Filename</th>
|
|
68
|
+
</tr>
|
|
69
|
+
</thead>
|
|
70
|
+
<tbody>
|
|
71
|
+
{% for label, filename in _attachments_ %}
|
|
72
|
+
<tr>
|
|
73
|
+
<td>{{ label }}</td>
|
|
74
|
+
<td>{{ filename }}</td>
|
|
75
|
+
</tr>
|
|
76
|
+
{% endfor %}
|
|
77
|
+
</tbody>
|
|
78
|
+
</table>
|
|
79
|
+
{% else %}
|
|
80
|
+
<p>No attachments included.</p>
|
|
81
|
+
{% endif %}
|
|
82
|
+
|
|
83
|
+
<h2>Request Metadata</h2>
|
|
84
|
+
{% if _meta_ %}
|
|
85
|
+
<table>
|
|
86
|
+
<tbody>
|
|
87
|
+
<tr>
|
|
88
|
+
<th>Client IP</th>
|
|
89
|
+
<td>{{ _meta_.client_ip | default('Unknown') }}</td>
|
|
90
|
+
</tr>
|
|
91
|
+
<tr>
|
|
92
|
+
<th>Received At</th>
|
|
93
|
+
<td>{{ _meta_.received_at | default('Unknown') }}</td>
|
|
94
|
+
</tr>
|
|
95
|
+
{% if _meta_.ip_chain and _meta_.ip_chain.length %}
|
|
96
|
+
<tr>
|
|
97
|
+
<th>IP Chain</th>
|
|
98
|
+
<td>{{ _meta_.ip_chain | join(', ') }}</td>
|
|
99
|
+
</tr>
|
|
100
|
+
{% endif %}
|
|
101
|
+
</tbody>
|
|
102
|
+
</table>
|
|
103
|
+
{% else %}
|
|
104
|
+
<p>No request metadata provided.</p>
|
|
105
|
+
{% endif %}
|
|
106
|
+
</body>
|
|
107
|
+
</html>
|