Compare commits
No commits in common. "main" and "0.3.2" have entirely different histories.
|
|
@ -42,8 +42,3 @@ deno install \
|
||||||
# OR
|
# OR
|
||||||
./cohamail <subcommand> -h
|
./cohamail <subcommand> -h
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
You can override default config and templates with your own in
|
|
||||||
`/etc/cohabit/mailer/(config|templates)/`.
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import { exists } from '@std/fs/exists'
|
import { fromFileUrl } from '@std/path'
|
||||||
import type { JSX } from 'preact'
|
import type { JSX } from 'preact'
|
||||||
import { EnumType } from '@cliffy/command'
|
import { EnumType } from '@cliffy/command'
|
||||||
import type { Template } from '../types.ts'
|
import type { Template } from '../types.ts'
|
||||||
import * as defaultTemplates from '../templates/mod.ts'
|
|
||||||
|
|
||||||
export const templates: Map<
|
export const templates: Map<
|
||||||
string,
|
string,
|
||||||
|
|
@ -12,38 +11,25 @@ export const templates: Map<
|
||||||
>
|
>
|
||||||
> = new Map()
|
> = new Map()
|
||||||
|
|
||||||
//Load default templates
|
const templatesDirUrl = import.meta.resolve('../templates')
|
||||||
for (const template of Object.values(defaultTemplates)) {
|
const templatesDir = fromFileUrl(templatesDirUrl)
|
||||||
//@ts-expect-error types are checked at runtime later
|
|
||||||
templates.set(template.name, template)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Load local templates
|
//Load templates dynamicaly
|
||||||
const basePath = '/etc/cohabit/mailer/templates'
|
for await (
|
||||||
|
const template of Deno.readDir(templatesDir)
|
||||||
if (await exists(basePath)) {
|
) {
|
||||||
for await (const template of Deno.readDir(basePath)) {
|
if (
|
||||||
if (!template.isFile) continue
|
template.isFile &&
|
||||||
if (!template.name.endsWith('.tsx')) continue
|
template.name.endsWith('.tsx') &&
|
||||||
if (template.name.startsWith('_')) continue
|
!template.name.startsWith('_')
|
||||||
|
) {
|
||||||
const mod = await import(`${basePath}/${template.name}`).catch(
|
const modPath = new URL(
|
||||||
checkFsErrors,
|
template.name,
|
||||||
|
`${import.meta.resolve('../templates')}/`,
|
||||||
)
|
)
|
||||||
|
const mod = await import(modPath.href)
|
||||||
templates.set(mod.default.name, mod.default)
|
templates.set(mod.default.name, mod.default)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkFsErrors(error: Error) {
|
|
||||||
if (error instanceof Deno.errors.PermissionDenied) {
|
|
||||||
throw new Error(
|
|
||||||
'unable to load config file due to read access permissions issues',
|
|
||||||
{
|
|
||||||
cause: error,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
|
|
||||||
export const templateType = new EnumType([...templates.keys()])
|
export const templateType = new EnumType([...templates.keys()])
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
import type { JsonValue } from '@std/json'
|
|
||||||
import defaultAccounts from './account.json' with { type: 'json' }
|
|
||||||
import defaultDkim from './dkim.json' with { type: 'json' }
|
|
||||||
|
|
||||||
function checkFsErrors(error: Error) {
|
|
||||||
if (error instanceof Deno.errors.NotFound) {
|
|
||||||
//use default config file
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (error instanceof Deno.errors.PermissionDenied) {
|
|
||||||
throw new Error(
|
|
||||||
'unable to load config file due to read access permissions issues',
|
|
||||||
{
|
|
||||||
cause: error,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
|
|
||||||
type JsonRecord = Record<string, JsonValue>
|
|
||||||
export type DkimRecord = {
|
|
||||||
domainName: string
|
|
||||||
keySelector: string
|
|
||||||
privateKey: string
|
|
||||||
}
|
|
||||||
export type AccountRecord = Record<string, {
|
|
||||||
name: string
|
|
||||||
address: string
|
|
||||||
}>
|
|
||||||
|
|
||||||
async function readJsonFile<
|
|
||||||
T extends JsonRecord,
|
|
||||||
>(path: string, defaultValue: T): Promise<T> {
|
|
||||||
const file = await Deno.readTextFile(path).catch(checkFsErrors)
|
|
||||||
const json = JSON.parse(file ?? '{}')
|
|
||||||
return { ...defaultValue, ...json }
|
|
||||||
}
|
|
||||||
|
|
||||||
const basePath = '/ect/cohabit/mailer/config'
|
|
||||||
|
|
||||||
export const accounts = await readJsonFile<AccountRecord>(
|
|
||||||
`${basePath}/account.json`,
|
|
||||||
defaultAccounts,
|
|
||||||
)
|
|
||||||
export const dkim = await readJsonFile<DkimRecord>(
|
|
||||||
`${basePath}/dkim.json`,
|
|
||||||
defaultDkim,
|
|
||||||
)
|
|
||||||
12
deno.json
12
deno.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@cohabit/mailer",
|
"name": "@cohabit/mailer",
|
||||||
"version": "0.5.2",
|
"version": "0.3.2",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./mod.ts",
|
".": "./mod.ts",
|
||||||
"./cli": "./cli.ts",
|
"./cli": "./cli.ts",
|
||||||
|
|
@ -8,8 +8,8 @@
|
||||||
"./templates": "./templates/mod.ts"
|
"./templates": "./templates/mod.ts"
|
||||||
},
|
},
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"compile": "deno compile --allow-read --allow-env --allow-net=0.0.0.0,jsr.io --allow-sys=osRelease,networkInterfaces --allow-run=/usr/sbin/sendmail,whoami --output=bin/mailer --target=x86_64-unknown-linux-gnu ./cli.ts",
|
"compile": "deno compile --allow-read --allow-env --allow-net=0.0.0.0 --allow-sys=osRelease,networkInterfaces --allow-run=/usr/sbin/sendmail,whoami --output=bin/mailer --target=x86_64-unknown-linux-gnu ./cli.ts",
|
||||||
"cli": "deno run --allow-read --allow-env --allow-net=0.0.0.0,jsr.io --allow-sys=osRelease,networkInterfaces --allow-run=/usr/sbin/sendmail,whoami ./cli.ts"
|
"cli": "deno run --allow-read --allow-env --allow-net=0.0.0.0 --allow-sys=osRelease,networkInterfaces --allow-run=/usr/sbin/sendmail,whoami ./cli.ts"
|
||||||
},
|
},
|
||||||
"fmt": {
|
"fmt": {
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
|
|
@ -19,8 +19,7 @@
|
||||||
"imports": {
|
"imports": {
|
||||||
"@cliffy/command": "jsr:@cliffy/command@^1.0.0-rc.5",
|
"@cliffy/command": "jsr:@cliffy/command@^1.0.0-rc.5",
|
||||||
"@cliffy/prompt": "jsr:@cliffy/prompt@^1.0.0-rc.5",
|
"@cliffy/prompt": "jsr:@cliffy/prompt@^1.0.0-rc.5",
|
||||||
"@std/fs": "jsr:@std/fs@^1.0.13",
|
"@std/path": "jsr:@std/path@^0.221.0",
|
||||||
"@std/json": "jsr:@std/json@^1.0.1",
|
|
||||||
"@types/nodemailer": "npm:@types/nodemailer@^6.4.15",
|
"@types/nodemailer": "npm:@types/nodemailer@^6.4.15",
|
||||||
"jsx-email": "npm:jsx-email@^1.10.12",
|
"jsx-email": "npm:jsx-email@^1.10.12",
|
||||||
"nodemailer": "npm:nodemailer@^6.9.13",
|
"nodemailer": "npm:nodemailer@^6.9.13",
|
||||||
|
|
@ -31,6 +30,5 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "preact"
|
"jsxImportSource": "preact"
|
||||||
},
|
}
|
||||||
"license": "MIT"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { accounts, dkim } from '../config/loader.ts'
|
import accounts from '../config/account.json' with { type: 'json' }
|
||||||
|
import dkim from '../config/dkim.json' with { type: 'json' }
|
||||||
|
|
||||||
export type AddressString = `${string}@${string}.${string}`
|
export type AddressString = `${string}@${string}.${string}`
|
||||||
|
|
||||||
|
|
@ -21,7 +22,7 @@ export class Contact {
|
||||||
throw new Error('unknown short name contact')
|
throw new Error('unknown short name contact')
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, address } = accounts[shortName]
|
const { name, address } = accounts[shortName as keyof typeof accounts]
|
||||||
|
|
||||||
if (typeof name !== 'string') {
|
if (typeof name !== 'string') {
|
||||||
throw new SyntaxError(
|
throw new SyntaxError(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// @deno-types="npm:@types/nodemailer@^6.4.15"
|
// @deno-types="@types/nodemailer"
|
||||||
import nodemailer from 'nodemailer'
|
import nodemailer from 'nodemailer'
|
||||||
import { dkim } from '../config/loader.ts'
|
import dkim from '../config/dkim.json' with { type: 'json' }
|
||||||
|
|
||||||
export async function transporter() {
|
export async function transporter() {
|
||||||
const dkimPath = dkim.privateKey
|
const dkimPath = dkim.privateKey
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue