diff --git a/.github/workflows/npmjs_publish.yaml b/.github/workflows/npmjs_publish.yaml
new file mode 100644
index 0000000..4097a88
--- /dev/null
+++ b/.github/workflows/npmjs_publish.yaml
@@ -0,0 +1,37 @@
+# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
+# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
+
+name: Publish @sctg/web-smtp-relay-client to NPMJS
+
+on:
+ release:
+ types: [created]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ - run: cd web-smtp-relay-client
+ - run: npm ci
+ - run: npm run build
+ - run: npm test
+
+ publish-npm:
+ needs: build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ registry-url: https://registry.npmjs.org/
+ - run: cd web-smtp-relay-client
+ - run: npm ci
+ - run: npm run build
+ - run: npm publish
+ env:
+ NODE_AUTH_TOKEN: ${{secrets.NPMJS_TOKEN}}
\ No newline at end of file
diff --git a/README.md b/README.md
index a5d3b26..378ddf6 100644
--- a/README.md
+++ b/README.md
@@ -125,31 +125,31 @@ This project includes a Helm chart for easy deployment to Kubernetes clusters. T
1. If you don't want to install the chart you can use our public Helm repository:
- ```bash
+```bash
- helm repo add highcanfly
- helm repo update highcanfly
+helm repo add highcanfly
+helm repo update highcanfly
- ```
+```
- Then install the chart:
+Then install the chart:
- ```bash
- helm upgrade --install --create-namespace --namespace web-smtp-relay web-smtp-relay highcanfly/web-smtp-relay --values values.yaml
- ```
+```bash
+helm upgrade --install --create-namespace --namespace web-smtp-relay web-smtp-relay highcanfly/web-smtp-relay --values values.yaml
+```
2. Clone the repository or download the Helm chart files.
3. Navigate to the chart directory:
- ```bash
- cd web-smtp-relay
- ```
+```bash
+cd web-smtp-relay
+```
4. Install the chart with the release name `my-web-smtp-relay`:
- ```bash
- helm install my-web-smtp-relay .
+```bash
+helm install my-web-smtp-relay .
```
### Customizing the Chart
diff --git a/web-smtp-relay-client/.gitignore b/web-smtp-relay-client/.gitignore
new file mode 100644
index 0000000..3e7f8dd
--- /dev/null
+++ b/web-smtp-relay-client/.gitignore
@@ -0,0 +1,115 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional stylelint cache
+.stylelintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+.env.production
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# VS Code directories
+.vscode/
+.history/
+
+# SvelteKit build / generate output
+.svelte-kit
+
+# Temporary folders
+tmp/
+temp/
\ No newline at end of file
diff --git a/web-smtp-relay-client/README.md b/web-smtp-relay-client/README.md
new file mode 100644
index 0000000..c577f7e
--- /dev/null
+++ b/web-smtp-relay-client/README.md
@@ -0,0 +1,39 @@
+# @sctg/web-smtp-relay-client
+
+A simple client for the web-smtp-relay server.
+
+## Installation
+
+```bash
+npm install @sctg/web-smtp-relay-client
+```
+
+## Usage
+
+```typescript
+import { WebSMTPRelayClient, WebSMTPRelayConfig, EmailMessage } from '@sctg/web-smtp-relay-client';
+
+const config: WebSMTPRelayConfig = {
+ scheme: 'https',
+ host: 'localhost',
+ port: 8080,
+ username: 'admin',
+ password: 'admin123'
+};
+
+const client = new WebSMTPRelayClient(config);
+
+const message: EmailMessage = {
+ subject: 'Test Subject',
+ body: 'This is a test email',
+ destinations: ['recipient@example.com']
+};
+
+client.sendEmail(message)
+ .then(() => console.log('Email sent successfully'))
+ .catch((error) => console.error('Error sending email:', error));
+```
+
+## License
+
+This project is licensed under the GNU Affero General Public License v3.0 (AGPLv3).
diff --git a/web-smtp-relay-client/package-lock.json b/web-smtp-relay-client/package-lock.json
new file mode 100644
index 0000000..ebdbabe
--- /dev/null
+++ b/web-smtp-relay-client/package-lock.json
@@ -0,0 +1,111 @@
+{
+ "name": "@sctg/web-smtp-relay-client",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@sctg/web-smtp-relay-client",
+ "version": "1.0.0",
+ "license": "AGPL-3.0",
+ "devDependencies": {
+ "@babel/parser": "^7.25.4",
+ "@babel/types": "^7.25.4",
+ "@types/node": "^20",
+ "typescript": "^5.5.4"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
+ "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
+ "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.25.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz",
+ "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.25.4"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.25.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz",
+ "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.24.8",
+ "@babel/helper-validator-identifier": "^7.24.7",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "20.16.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.1.tgz",
+ "integrity": "sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.19.2"
+ }
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
+ "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+ "dev": true,
+ "license": "MIT"
+ }
+ }
+}
diff --git a/web-smtp-relay-client/package.json b/web-smtp-relay-client/package.json
new file mode 100644
index 0000000..da8fe5d
--- /dev/null
+++ b/web-smtp-relay-client/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@sctg/web-smtp-relay-client",
+ "version": "1.0.0",
+ "description": "A simple client for the web-smtp-relay server",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "private": false,
+ "scripts": {
+ "build": "tsc",
+ "prepublishOnly": "npm run build"
+ },
+ "keywords": ["smtp", "relay", "client"],
+ "author": "Ronan LE MEILLAT",
+ "license": "AGPL-3.0",
+ "devDependencies": {
+ "typescript": "^5.5.4",
+ "@types/node": "^20",
+ "@babel/parser": "^7.25.4",
+ "@babel/types":"^7.25.4"
+ },
+ "files": [
+ "dist/**/*"
+ ]
+ }
\ No newline at end of file
diff --git a/web-smtp-relay-client/src/index.ts b/web-smtp-relay-client/src/index.ts
new file mode 100644
index 0000000..55c6605
--- /dev/null
+++ b/web-smtp-relay-client/src/index.ts
@@ -0,0 +1,39 @@
+export interface WebSMTPRelayConfig {
+ scheme: string;
+ host: string;
+ port: number;
+ username: string;
+ password: string;
+}
+
+export interface EmailMessage {
+ subject: string;
+ body: string;
+ destinations: string[];
+}
+
+export class WebSMTPRelayClient {
+ private config: WebSMTPRelayConfig;
+
+ constructor(config: WebSMTPRelayConfig) {
+ this.config = config;
+ }
+
+ async sendEmail(message: EmailMessage): Promise {
+ const url = `${this.config.scheme}://${this.config.host}:${this.config.port}/send`;
+ const auth = Buffer.from(`${this.config.username}:${this.config.password}`).toString('base64');
+
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Basic ${auth}`,
+ },
+ body: JSON.stringify(message),
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ }
+}
\ No newline at end of file
diff --git a/web-smtp-relay-client/tsconfig.json b/web-smtp-relay-client/tsconfig.json
new file mode 100644
index 0000000..559ce38
--- /dev/null
+++ b/web-smtp-relay-client/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext",
+ "importHelpers": true,
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "declaration": true,
+ "skipLibCheck": true,
+ "outDir": "./dist",
+ "strict": true,
+ },
+ "include": [
+ "src"
+ ],
+ "exclude": [
+ "node_modules",
+ "**/__tests__/*"
+ ]
+}
\ No newline at end of file