A system for building static webapps
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(hono): add smtp as default email adapter

+74 -1
+13
deno.lock
··· 64 64 "jsr:@std/toml@^1.0.3": "1.0.11", 65 65 "jsr:@std/ulid@1": "1.0.0", 66 66 "jsr:@std/yaml@^1.0.5": "1.1.0", 67 + "jsr:@upyo/core@0.4": "0.4.0", 68 + "jsr:@upyo/smtp@0.4": "0.4.0", 67 69 "jsr:@zaubrik/djwt@^3.0.2": "3.0.2", 68 70 "jsr:@zip-js/zip-js@^2.7.52": "2.8.26", 69 71 "jsr:@zod/zod@^4.3.6": "4.4.2", ··· 344 346 }, 345 347 "@std/yaml@1.1.0": { 346 348 "integrity": "fc1c5c63e05c4c5eb6118355f557958035d41940d6c29d35b306ef7155d6edb0" 349 + }, 350 + "@upyo/core@0.4.0": { 351 + "integrity": "ae4c8470d83166b4e360c5a79cdebb3f189b66d1142724f449d1d8acbc380e19" 352 + }, 353 + "@upyo/smtp@0.4.0": { 354 + "integrity": "0e8cacb12156352ed37f13415d6bfd031a96edf558551b3414121eaa0afbdf0d", 355 + "dependencies": [ 356 + "jsr:@upyo/core" 357 + ] 347 358 }, 348 359 "@zaubrik/djwt@3.0.2": { 349 360 "integrity": "8070adaa49cd9e5d2b8ae82fd461132c966ef2f8ff8378db4a4da8df4f17c664", ··· 1313 1324 "jsr:@civility/store@^1.0.0-beta.10", 1314 1325 "jsr:@hono/hono@^4.12.16", 1315 1326 "jsr:@std/crypto@^1.1.0", 1327 + "jsr:@upyo/core@0.4", 1328 + "jsr:@upyo/smtp@0.4", 1316 1329 "jsr:@zaubrik/djwt@^3.0.2", 1317 1330 "jsr:@zod/zod@^4.4.2", 1318 1331 "npm:@hono/swagger-ui@~0.6.1",
+4 -1
packages/hono/deno.json
··· 12 12 "./sync": "./sync/mod.ts", 13 13 "./sync/deno-kv": "./sync/adapters/deno-kv.ts", 14 14 "./storage/s3": "./storage/s3.ts", 15 - "./storage/bunny": "./storage/bunny.ts" 15 + "./storage/bunny": "./storage/bunny.ts", 16 + "./email/smtp": "./email/smtp.ts" 16 17 }, 17 18 "imports": { 18 19 "@bradenmacdonald/s3-lite-client": "jsr:@bradenmacdonald/s3-lite-client@^0.9.6", ··· 25 26 "@oslojs/encoding": "npm:@oslojs/encoding@^1.1.0", 26 27 "@oslojs/otp": "npm:@oslojs/otp@^1.1.0", 27 28 "@std/crypto": "jsr:@std/crypto@^1.1.0", 29 + "@upyo/core": "jsr:@upyo/core@^0.4.0", 30 + "@upyo/smtp": "jsr:@upyo/smtp@^0.4.0", 28 31 "@zaubrik/djwt": "jsr:@zaubrik/djwt@^3.0.2", 29 32 "@zod/zod": "jsr:@zod/zod@^4.4.2", 30 33 "hono": "npm:hono@^4.12.16"
+43
packages/hono/email/smtp.ts
··· 1 + import { createMessage } from '@upyo/core' 2 + import { SmtpTransport } from '@upyo/smtp' 3 + import type { EmailAdapter } from '../shared/types.ts' 4 + 5 + export interface SmtpEmailConfig { 6 + host: string 7 + port?: number 8 + /** Use TLS (port 465). For STARTTLS on port 587, leave false. */ 9 + secure?: boolean 10 + username?: string 11 + password?: string 12 + /** From address, e.g. "Civility <noreply@example.com>" */ 13 + from: string 14 + } 15 + 16 + export function createSmtpAdapter(config: SmtpEmailConfig): EmailAdapter { 17 + const transport = new SmtpTransport({ 18 + host: config.host, 19 + port: config.port ?? 587, 20 + secure: config.secure ?? false, 21 + auth: config.username !== undefined 22 + ? { user: config.username, pass: config.password ?? '' } 23 + : undefined, 24 + }) 25 + 26 + return { 27 + async send({ to, subject, html, text }) { 28 + const message = createMessage({ 29 + from: config.from, 30 + to, 31 + subject, 32 + content: html ? { html, text } : { text: text ?? '' }, 33 + }) 34 + 35 + const receipt = await transport.send(message) 36 + if (!receipt.successful) { 37 + throw new Error( 38 + `SMTP send failed: ${receipt.errorMessages.join(', ')}`, 39 + ) 40 + } 41 + }, 42 + } 43 + }
+14
packages/hono/main.ts
··· 1 1 #!/usr/bin/env -S deno run -A 2 2 import { createServer } from './mod.ts' 3 3 import { createBunnyStorage } from './storage/bunny.ts' 4 + import { createSmtpAdapter } from './email/smtp.ts' 4 5 5 6 const kv = await Deno.openKv() 6 7 ··· 10 11 kv, 11 12 }) 12 13 14 + const smtpHost = Deno.env.get('SMTP_HOST') 15 + const email = smtpHost 16 + ? createSmtpAdapter({ 17 + host: smtpHost, 18 + port: Deno.env.get('SMTP_PORT') ? Number(Deno.env.get('SMTP_PORT')) : undefined, 19 + secure: Deno.env.get('SMTP_SECURE') === 'true', 20 + username: Deno.env.get('SMTP_USER'), 21 + password: Deno.env.get('SMTP_PASS'), 22 + from: Deno.env.get('SMTP_FROM') ?? `noreply@${smtpHost}`, 23 + }) 24 + : undefined 25 + 13 26 const app = await createServer({ 14 27 kv, 15 28 objectStorage, 29 + email, 16 30 }) 17 31 18 32 Deno.serve({ port: 7070 }, app.fetch)