{
  "slug": "nodemailer-smtp",
  "runtimes": {
    "node": {
      "frameworks": {
        "express": {
          "dependencies": {
            "runtime": [
              "nodemailer"
            ],
            "dev": [
              "@types/nodemailer"
            ]
          },
          "env": [
            "SMTP_PORT",
            "SMTP_HOST",
            "SMTP_PASS",
            "SMTP_USER",
            "EMAIL_FROM"
          ],
          "architectures": {
            "mvc": {
              "files": [
                {
                  "type": "file",
                  "path": "src/configs/nodemailer.ts",
                  "content": "import nodemailer from \"nodemailer\";\r\nimport env from \"./env\";\r\n\r\nlet transporter: nodemailer.Transporter | null = null;\r\n\r\nexport function getTransporter() {\r\n  if (transporter) return transporter;\r\n  const host = env.SMTP_HOST;\r\n  const port = Number(env.SMTP_PORT || 465);\r\n  const user = env.SMTP_USER;\r\n  const pass = env.SMTP_PASS;\r\n  const from = env.EMAIL_FROM;\r\n  if (!host || !user || !pass || !from) {\r\n    throw new Error(\"SMTP/EMAIL env not configured\");\r\n  }\r\n\r\n  transporter = nodemailer.createTransport({\r\n    host,\r\n    port,\r\n    secure: port === 465,\r\n    auth: { user, pass }\r\n  });\r\n  return transporter;\r\n}\r\n/**\r\n *? USAGE:\r\n  export async function sendEmail({ from, email, subject, html }) {\r\n  const transporter = getTransporter();\r\n\r\n  return transporter\r\n    .sendMail({\r\n      from: from || `<${env.EMAIL_FROM}>`,\r\n      to: email,\r\n      subject,\r\n      html\r\n    })\r\n    .catch(() => {\r\n      throw new Error(\"Failed to send email\");\r\n    });\r\n }\r\n */\r\n"
                },
                {
                  "type": "file",
                  "path": "src/configs/env.ts",
                  "content": "import dotenv from \"dotenv-flow\";\r\ndotenv.config();\r\nimport { z } from \"zod\";\r\n\r\nexport const envSchema = z.object({\r\n  SMTP_HOST: z.string(),\r\n  SMTP_PORT: z\r\n    .string()\r\n    .regex(/^\\d+$/, \"SMTP_PORT must be a number\")\r\n    .transform(Number),\r\n  SMTP_USER: z.string(),\r\n  SMTP_PASS: z.string(),\r\n  EMAIL_FROM: z.email()\r\n});\r\n\r\nexport type Env = z.infer<typeof envSchema>;\r\n\r\nconst result = envSchema.safeParse(process.env);\r\n\r\nif (!result.success) {\r\n  console.error(\"❌ Invalid environment configuration\");\r\n  console.error(z.prettifyError(result.error));\r\n  process.exit(1);\r\n}\r\n\r\nexport const env: Readonly<Env> = Object.freeze(result.data);\r\n\r\nexport default env;\r\n"
                }
              ]
            },
            "feature": {
              "files": [
                {
                  "type": "file",
                  "path": "src/shared/configs/nodemailer.ts",
                  "content": "import nodemailer from \"nodemailer\";\r\nimport env from \"./env\";\r\n\r\nlet transporter: nodemailer.Transporter | null = null;\r\n\r\nexport function getTransporter() {\r\n  if (transporter) return transporter;\r\n  const host = env.SMTP_HOST;\r\n  const port = Number(env.SMTP_PORT || 465);\r\n  const user = env.SMTP_USER;\r\n  const pass = env.SMTP_PASS;\r\n  const from = env.EMAIL_FROM;\r\n  if (!host || !user || !pass || !from) {\r\n    throw new Error(\"SMTP/EMAIL env not configured\");\r\n  }\r\n\r\n  transporter = nodemailer.createTransport({\r\n    host,\r\n    port,\r\n    secure: port === 465,\r\n    auth: { user, pass }\r\n  });\r\n  return transporter;\r\n}\r\n/**\r\n *? USAGE:\r\n  export async function sendEmail({ from, email, subject, html }) {\r\n  const transporter = getTransporter();\r\n\r\n  return transporter\r\n    .sendMail({\r\n      from: from || `<${env.EMAIL_FROM}>`,\r\n      to: email,\r\n      subject,\r\n      html\r\n    })\r\n    .catch(() => {\r\n      throw new Error(\"Failed to send email\");\r\n    });\r\n }\r\n */\r\n"
                },
                {
                  "type": "file",
                  "path": "src/shared/configs/env.ts",
                  "content": "import dotenv from \"dotenv-flow\";\r\ndotenv.config();\r\nimport { z } from \"zod\";\r\n\r\nexport const envSchema = z.object({\r\n  SMTP_HOST: z.string(),\r\n  SMTP_PORT: z\r\n    .string()\r\n    .regex(/^\\d+$/, \"SMTP_PORT must be a number\")\r\n    .transform(Number),\r\n  SMTP_USER: z.string(),\r\n  SMTP_PASS: z.string(),\r\n  EMAIL_FROM: z.email()\r\n});\r\n\r\nexport type Env = z.infer<typeof envSchema>;\r\n\r\nconst result = envSchema.safeParse(process.env);\r\n\r\nif (!result.success) {\r\n  console.error(\"❌ Invalid environment configuration\");\r\n  console.error(z.prettifyError(result.error));\r\n  process.exit(1);\r\n}\r\n\r\nexport const env: Readonly<Env> = Object.freeze(result.data);\r\n\r\nexport default env;\r\n"
                }
              ]
            }
          }
        }
      }
    }
  }
}
