Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"plugins/session",
"plugins/rate-limit",
"plugins/edge",
"plugins/jwt"
"plugins/jwt",
"plugins/mailer"
],
"author": "angga7togk",
"license": "MIT",
Expand Down
10 changes: 10 additions & 0 deletions plugins/mailer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# @gaman/mailer

## 1.0.0

- Initial release of the Gaman mailer plugin
- Added support for sending emails using SMTP via nodemailer
- Introduced Mail class for composing email messages with from, to, subject, text, and HTML body
- Added Mailer class with features for delayed sending, timeouts, scheduling, and debug mode
- Configurable SMTP settings with defaults for host, port, and security
- Peer dependencies: nodemailer and @types/nodemailer
22 changes: 22 additions & 0 deletions plugins/mailer/Mail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Mail as LikeMail } from './types';

export default class Mail {
from: string;
to: string;
subject: string;
text: string;
body: string;

async create(mail: LikeMail) {
this.from = mail.from;
this.to = mail.to;
this.subject = mail.subject;
this.text = mail.text;

if (typeof mail.body !== 'string') {
this.body = await mail.body.text();
} else {
this.body = mail.body;
}
}
}
85 changes: 85 additions & 0 deletions plugins/mailer/Mailer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import nodemailer from 'nodemailer';
import { Mail, MailerSentOptions, Transport } from './types';
import {
DEFAULT_SMTP_HOST,
DEFAULT_SMTP_PORT,
DEFAULT_SMTP_SECURE,
} from './config';

export default class Mailer {
private transporter: Transport;

constructor(private trans: Transport) {
this.transporter = {
host: trans.host || DEFAULT_SMTP_HOST,
port: trans.port || DEFAULT_SMTP_PORT,
secure: trans.secure || DEFAULT_SMTP_SECURE,
auth: {
user: trans.auth.user,
password: trans.auth.password,
},
};
}

async wait(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}

async sendMail(mail: Mail, options: MailerSentOptions): Promise<boolean> {
return new Promise(async (resolve, reject) => {
if (!this.transporter) {
reject(new Error('Transport not initialized'));
return;
}

const transport = nodemailer.createTransport(this.transporter);

if (options.delay) {
await this.wait(options.delay);
}

if (options.timeout) {
setTimeout(() => {
console.error('Timeout');
reject(false);
}, options.timeout);
}

if (options.scheduled_at) {
const scheduledDate = new Date(options.scheduled_at);
const now = new Date();

setTimeout(async () => {
await this.sendMail(mail, options);
}, scheduledDate.getTime() - now.getTime());
}

transport.sendMail(
{
from: mail.from,
to: mail.to,
subject: mail.subject,
text: mail.text,
html: mail.body as string,
},
(error, info) => {
if (error) {
if (options.debug) {
console.error(error);
}

reject(false);
} else {
if (options.debug) {
console.table(info);
}

resolve(true);
}
},
);

// end method
});
}
}
90 changes: 90 additions & 0 deletions plugins/mailer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# @gaman/mailer

A plugin for the Gaman framework to send emails using SMTP via nodemailer.

## Installation

Ensure you have the required peer dependencies installed:

```bash
npm install @gaman/mailer
```

## Configuration

Configure your SMTP settings in your Gaman application. You can customize the transport options:

```typescript
import { Transport } from '@gaman/mailer';

const transport: Transport = {
host: 'smtp.gmail.com',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: 'your-email@example.com',
password: 'your-password',
},
};
```

Defaults are provided if not specified:
- Host: `smtp.example.com`
- Port: `587`
- Secure: `false`

## Usage

### Step 1: Create a Mail Instance

Use the `Mail` class to compose your email:

```typescript
import Mail from '@gaman/mailer/Mail';

const mail = new Mail();
await mail.create({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'Test Email',
text: 'This is a plain text email.',
body: '<h1>This is an HTML email.</h1>', // or a Response object for dynamic content
});
```

### Step 2: Send the Email

Use the `Mailer` class to send the email:

```typescript
import Mailer from '@gaman/mailer/Mailer';
import { MailerSentOptions } from '@gaman/mailer';

const mailer = new Mailer(transport);

const options: MailerSentOptions = {
debug: true, // Enable debug logging
delay: 1000, // Delay sending by 1 second (optional)
timeout: 5000, // Timeout after 5 seconds (optional)
scheduled_at: '2023-10-01T10:00:00Z', // Schedule for later (optional)
};

try {
const success = await mailer.sendMail(mail, options);
if (success) {
console.log('Email sent successfully');
}
} catch (error) {
console.error('Failed to send email:', error);
}
```

### API Reference

- **Mail Class**: Composes email messages.
- `create(mail: LikeMail): Promise<void>`: Initializes the mail object.

- **Mailer Class**: Handles sending emails.
- `sendMail(mail: Mail, options: MailerSentOptions): Promise<boolean>`: Sends the email and returns success status.

For more details, refer to the source code in `Mail.ts` and `Mailer.ts`.
3 changes: 3 additions & 0 deletions plugins/mailer/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const DEFAULT_SMTP_HOST = 'smtp.example.com';
export const DEFAULT_SMTP_PORT = 587;
export const DEFAULT_SMTP_SECURE = false;
2 changes: 2 additions & 0 deletions plugins/mailer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Mail';
export * from './Mailer';
Loading