New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

gmail-node-mailer

Package Overview
Dependencies
Maintainers
1
Versions
73
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gmail-node-mailer - npm Package Compare versions

Comparing version 1.6.607 to 1.7.1

dist/utils/encodeSubject.d.ts

4

dist/__tests__/isValidEmail.test.js

@@ -6,7 +6,7 @@ "use strict";

test('should return true for a valid email', () => {
expect((0, isValidEmail_1.isValidEmail)('test@example.com')).toBe(true);
expect((0, isValidEmail_1.isValidEmail)({ email: 'test@example.com' }).result).toBe(true);
});
test('should return false for an invalid email', () => {
expect((0, isValidEmail_1.isValidEmail)('testexample.com')).toBe(false);
expect((0, isValidEmail_1.isValidEmail)({ email: 'testexample.com' }).result).toBe(false);
});
});
import { gmail_v1 } from 'googleapis';
import { ISendEmailParams, ISendEmailResponse } from '../types';
import { ISendEmailParams, ISendEmailFunctionResponse } from '../types';
/**
* Sends an email using the Gmail API client, supporting both HTML and plain text content.
* Sends an email using the Gmail API client, supporting both HTML and plain text content. It automatically
* MIME encodes the subject if it isn't already and determines whether the message content is HTML or plain text
* to format the email appropriately.
*
* @param {gmail_v1.Gmail} gmailClient The Gmail API client instance.
* @param {ISendEmailParams} params Parameters required for sending the email, including both text and HTML versions of the message.
* @returns {Promise<ISendEmailResponse>} The result of the email sending operation.
* @param {ISendEmailParams} params Parameters required for sending the email, including sender, recipient, subject, and message content.
* @returns {Promise<ISendEmailFunctionResponse>} The result of the email sending operation, including whether the email was sent successfully, the status message, and the raw Gmail API response.
*/
export declare function sendEmail(gmailClient: gmail_v1.Gmail, { senderEmail, recipientEmail, subject, encodedSubject, textMessage, htmlMessage }: ISendEmailParams): Promise<ISendEmailResponse>;
export declare function sendEmailFunction(gmailClient: gmail_v1.Gmail, { senderEmail, recipientEmail, subject, message }: ISendEmailParams): Promise<ISendEmailFunctionResponse>;

@@ -12,108 +12,60 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.sendEmail = void 0;
exports.sendEmailFunction = void 0;
const isSubjectMimeEncoded_1 = require("../utils/isSubjectMimeEncoded");
const encodeSubject_1 = require("../utils/encodeSubject");
const isHtmlMessage_1 = require("../utils/isHtmlMessage");
/**
* Sends an email using the Gmail API client, supporting both HTML and plain text content.
* Sends an email using the Gmail API client, supporting both HTML and plain text content. It automatically
* MIME encodes the subject if it isn't already and determines whether the message content is HTML or plain text
* to format the email appropriately.
*
* @param {gmail_v1.Gmail} gmailClient The Gmail API client instance.
* @param {ISendEmailParams} params Parameters required for sending the email, including both text and HTML versions of the message.
* @returns {Promise<ISendEmailResponse>} The result of the email sending operation.
* @param {ISendEmailParams} params Parameters required for sending the email, including sender, recipient, subject, and message content.
* @returns {Promise<ISendEmailFunctionResponse>} The result of the email sending operation, including whether the email was sent successfully, the status message, and the raw Gmail API response.
*/
function sendEmail(gmailClient_1, _a) {
return __awaiter(this, arguments, void 0, function* (gmailClient, { senderEmail, recipientEmail, subject, encodedSubject, textMessage, htmlMessage }) {
if (!gmailClient) {
return {
status: false,
statusCode: null,
statusText: null,
responseUrl: null,
message: 'The Gmail client has not been initialized. Please call initializeClient first.',
responseData: null,
headers: null,
};
function sendEmailFunction(gmailClient_1, _a) {
return __awaiter(this, arguments, void 0, function* (gmailClient, { senderEmail, recipientEmail, subject, message }) {
let finalSubject = subject; // Initialize finalSubject with the original subject
const encodedCheck = (0, isSubjectMimeEncoded_1.isSubjectMimeEncoded)({ subject });
if (!encodedCheck.result) {
// If subject is not MIME encoded, encode it
const { status, result } = (0, encodeSubject_1.encodeSubject)({ subject });
if (status) {
finalSubject = result;
}
}
// Check for subject
if (!subject && !encodedSubject) {
return {
status: false,
statusCode: null,
statusText: null,
responseUrl: null,
message: 'A subject or encodedSubject must be provided.',
responseData: null,
headers: null,
};
// Determine if the message is HTML or plain text
const htmlCheck = (0, isHtmlMessage_1.isHtmlMessage)({ message });
let mimeMessage = `From: ${senderEmail}\r\nTo: ${recipientEmail}\r\nSubject: ${finalSubject}\r\n`;
// Construct MIME message based on HTML check result
const boundary = "----=_NextPart_" + Math.random().toString(36).substr(2, 9);
if (htmlCheck.result) {
mimeMessage += `Content-Type: multipart/alternative; boundary=${boundary}\r\n\r\n` +
`--${boundary}\r\n` +
`Content-Type: text/html; charset=UTF-8\r\n\r\n` +
`${message}\r\n` +
`--${boundary}--`;
}
// Use subject if both are provided
const finalSubject = subject || encodedSubject;
// Check for message content
if (!textMessage && !htmlMessage) {
return {
status: false,
statusCode: null,
statusText: null,
responseUrl: null,
message: 'At least one of textMessage or htmlMessage must be provided.',
responseData: null,
headers: null,
};
else {
mimeMessage += `Content-Type: text/plain; charset=UTF-8\r\n\r\n${message}`;
}
// Generate a boundary string for the MIME message
const boundary = "----=_NextPart_" + Math.random().toString(36).substr(2, 9);
// Construct the MIME message with both plain text and HTML parts
const mimeMessage = [
`From: ${senderEmail}`,
`To: ${recipientEmail}`,
`Subject: ${finalSubject}`, // Use the finalSubject here
`Content-Type: multipart/alternative; boundary=${boundary}`,
"",
`--${boundary}`,
"Content-Type: text/plain; charset=UTF-8",
"",
textMessage || " ", // Provide a fallback if textMessage is not provided
`--${boundary}`,
"Content-Type: text/html; charset=UTF-8",
"",
htmlMessage || "<p></p>", // Provide a minimal HTML structure as a fallback if htmlMessage is not provided
`--${boundary}--`,
].join("\r\n");
const encodedEmail = Buffer.from(mimeMessage, 'utf-8').toString('base64').replace(/\+/g, '-').replace(/\//g, '_');
try {
const response = yield gmailClient.users.messages.send({
const gmailResponse = yield gmailClient.users.messages.send({
userId: 'me',
requestBody: { raw: encodedEmail },
});
if (response.status < 200 || response.status >= 300) {
return {
status: false,
statusCode: response.status,
statusText: response.statusText,
responseUrl: response.request.responseURL,
message: `Failed to send email. Status: ${response.status}`,
responseData: response.data,
headers: response.headers,
};
}
return {
status: true,
statusCode: response.status,
statusText: response.statusText,
responseUrl: response.request.responseURL,
message: `Email successfully sent to ${recipientEmail}.`,
responseData: response.data,
headers: response.headers,
sent: gmailResponse.status >= 200 && gmailResponse.status < 300,
message: gmailResponse.status >= 200 && gmailResponse.status < 300 ?
`Email successfully sent to ${recipientEmail}.` :
`Failed to send email. Status: ${gmailResponse.status}`,
gmailResponse: gmailResponse,
};
}
catch (error) {
return {
status: true,
statusCode: null,
statusText: null,
responseUrl: null,
message: `An error occurred while sending the email: ${error.message}`,
responseData: null,
headers: null,
};
return { sent: false, message: `An error occurred while sending the email: ${error.message}`, gmailResponse: null };
}
});
}
exports.sendEmail = sendEmail;
exports.sendEmailFunction = sendEmailFunction;

@@ -7,16 +7,36 @@ import { gmail_v1 } from 'googleapis';

/**
* Initializes the Gmail API client with provided configuration.
* Validates the Gmail sender email and uses service account credentials for authentication.
* Initializes the Gmail API client using the provided or environment-based configuration. This method validates the
* Gmail sender's email address and authenticates using service account credentials. It supports multiple ways to provide
* these credentials: directly via parameters, loaded from a file path, or parsed from an environment variable.
*
* @param {IInitializeClientParams} config - Configuration for Gmail client initialization.
* @returns {Promise<IInitializeClientResult>} - Result of initialization attempt.
* The service account credentials can be provided in several ways:
* - Directly via the method parameters.
* - By specifying a file path to load the credentials from (`gmailServiceAccountPath`).
* - Through the `GMAIL_MAILER_SERVICE_ACCOUNT` environment variable, which should contain the JSON representation
* of the service account credentials.
*
* If the credentials are not directly provided, the method first attempts to load them from the specified file path.
* If no valid path is provided or if the file does not contain valid credentials, it then attempts to parse the credentials
* from the `GMAIL_MAILER_SERVICE_ACCOUNT` environment variable.
*
* This flexible initialization approach allows the GmailMailer to be configured seamlessly across different environments,
* making it highly suitable for both development and production use. For instance, in development, you can provide the
* `GMAIL_MAILER_SERVICE_ACCOUNT_PATH` environment variable pointing to a local JSON file with your service account credentials.
* In production environments, such as on a Digital Ocean server or other cloud environments where direct file access may be
* restricted or inconvenient, you can directly provide the service account credentials as a JSON string via the
* `GMAIL_MAILER_SERVICE_ACCOUNT` environment variable. This design ensures that the package automatically works in both environments
* without the need for code changes, simplifying deployment and integration.
*
* @param {IInitializeClientParams} config - Configuration for Gmail client initialization, including service account details and sender email.
* @returns {Promise<IInitializeClientResult>} - The result of the initialization attempt, including the status, initialized Gmail client instance, and any error messages.
*/
initializeClient({ gmailServiceAccount, gmailServiceAccountPath, gmailSenderEmail, }: IInitializeClientParams): Promise<IInitializeClientResult>;
/**
* Sends an email using the initialized Gmail API client. Validates sender email if not provided.
*
* @param {ISendEmailParams} params - Email sending parameters.
* @returns {Promise<ISendEmailResponse>} - Result of the email sending operation.
*/
* Sends an email using the initialized Gmail API client. It validates the sender email, ensures a subject
* is provided, and verifies that the message content is present before proceeding.
*
* @param {ISendEmailParams} params Parameters for sending the email, including recipient, sender, subject, and message.
* @returns {Promise<ISendEmailResponse>} The result of the email sending operation, including status and any response details.
*/
sendEmail(params: ISendEmailParams): Promise<ISendEmailResponse>;
}

@@ -19,2 +19,3 @@ "use strict";

const gmailServiceAccountConfig_1 = require("./utils/gmailServiceAccountConfig");
const generateErrorResponse_1 = require("./utils/generateErrorResponse");
class GmailMailer {

@@ -26,7 +27,26 @@ constructor(gmailClient) {

/**
* Initializes the Gmail API client with provided configuration.
* Validates the Gmail sender email and uses service account credentials for authentication.
* Initializes the Gmail API client using the provided or environment-based configuration. This method validates the
* Gmail sender's email address and authenticates using service account credentials. It supports multiple ways to provide
* these credentials: directly via parameters, loaded from a file path, or parsed from an environment variable.
*
* @param {IInitializeClientParams} config - Configuration for Gmail client initialization.
* @returns {Promise<IInitializeClientResult>} - Result of initialization attempt.
* The service account credentials can be provided in several ways:
* - Directly via the method parameters.
* - By specifying a file path to load the credentials from (`gmailServiceAccountPath`).
* - Through the `GMAIL_MAILER_SERVICE_ACCOUNT` environment variable, which should contain the JSON representation
* of the service account credentials.
*
* If the credentials are not directly provided, the method first attempts to load them from the specified file path.
* If no valid path is provided or if the file does not contain valid credentials, it then attempts to parse the credentials
* from the `GMAIL_MAILER_SERVICE_ACCOUNT` environment variable.
*
* This flexible initialization approach allows the GmailMailer to be configured seamlessly across different environments,
* making it highly suitable for both development and production use. For instance, in development, you can provide the
* `GMAIL_MAILER_SERVICE_ACCOUNT_PATH` environment variable pointing to a local JSON file with your service account credentials.
* In production environments, such as on a Digital Ocean server or other cloud environments where direct file access may be
* restricted or inconvenient, you can directly provide the service account credentials as a JSON string via the
* `GMAIL_MAILER_SERVICE_ACCOUNT` environment variable. This design ensures that the package automatically works in both environments
* without the need for code changes, simplifying deployment and integration.
*
* @param {IInitializeClientParams} config - Configuration for Gmail client initialization, including service account details and sender email.
* @returns {Promise<IInitializeClientResult>} - The result of the initialization attempt, including the status, initialized Gmail client instance, and any error messages.
*/

@@ -36,5 +56,9 @@ initializeClient(_a) {

try {
if (!gmailSenderEmail || !(0, isValidEmail_1.isValidEmail)(gmailSenderEmail)) {
if (!gmailSenderEmail || !(0, isValidEmail_1.isValidEmail)({ email: gmailSenderEmail }).result) {
throw new Error("Invalid or missing Gmail sender's email.");
}
// If gmailServiceAccountPath is not provided, use the environment variable
if (!gmailServiceAccountPath) {
gmailServiceAccountPath = process.env.GMAIL_MAILER_SERVICE_ACCOUNT_PATH;
}
if (!gmailServiceAccount && gmailServiceAccountPath) {

@@ -45,4 +69,13 @@ const serviceAccountResult = yield (0, parseServiceAccountFile_1.parseServiceAccountFile)({ filePath: gmailServiceAccountPath });

}
gmailServiceAccountConfig_1.gmailServiceAccountConfig.setServiceAccount(serviceAccountResult.serviceAccount);
gmailServiceAccount = serviceAccountResult.serviceAccount; // Set the gmailServiceAccount with the loaded service account
}
// Check for service account JSON in GMAIL_MAILER_SERVICE_ACCOUNT environment variable as a fallback
if (!gmailServiceAccount && process.env.GMAIL_MAILER_SERVICE_ACCOUNT) {
try {
gmailServiceAccount = JSON.parse(process.env.GMAIL_MAILER_SERVICE_ACCOUNT);
}
catch (error) {
throw new Error("Failed to parse service account from GMAIL_MAILER_SERVICE_ACCOUNT environment variable.");
}
}
if (!gmailServiceAccount) {

@@ -70,34 +103,42 @@ throw new Error("Service account configuration is missing.");

/**
* Sends an email using the initialized Gmail API client. Validates sender email if not provided.
*
* @param {ISendEmailParams} params - Email sending parameters.
* @returns {Promise<ISendEmailResponse>} - Result of the email sending operation.
*/
* Sends an email using the initialized Gmail API client. It validates the sender email, ensures a subject
* is provided, and verifies that the message content is present before proceeding.
*
* @param {ISendEmailParams} params Parameters for sending the email, including recipient, sender, subject, and message.
* @returns {Promise<ISendEmailResponse>} The result of the email sending operation, including status and any response details.
*/
sendEmail(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d;
if (!this.gmailClient) {
return {
status: false,
message: 'Gmail client not initialized. Please initialize before sending emails.',
responseData: null,
statusCode: null,
statusText: null,
responseUrl: null,
headers: null,
};
return (0, generateErrorResponse_1.generateErrorResponse)({ message: 'The Gmail client has not been initialized. Please call initializeClient first.' });
}
const senderEmail = params.senderEmail || emailConfig_1.emailConfig.getGmailSenderEmail();
if (!senderEmail) {
return (0, generateErrorResponse_1.generateErrorResponse)({ message: 'Sender email not configured. Please provide a sender email.' });
}
if (!params.subject) {
return (0, generateErrorResponse_1.generateErrorResponse)({ message: 'A subject (text or encoded) must be provided.' });
}
if (!params.message) {
return (0, generateErrorResponse_1.generateErrorResponse)({ message: 'At least one of textMessage or htmlMessage must be provided.' });
}
const adjustedParams = Object.assign(Object.assign({}, params), { senderEmail });
// Assuming sendEmailFunction is properly imported and utilized
const sendResult = yield (0, sendEmail_1.sendEmailFunction)(this.gmailClient, adjustedParams);
if (!sendResult.sent) {
// Handling failure from the sendEmail function
return (0, generateErrorResponse_1.generateErrorResponse)({ message: sendResult.message });
}
else {
// Handling success from the sendEmail function
return {
status: false,
message: 'Sender email not configured. Please provide a sender email.',
responseData: null,
statusCode: null,
statusText: null,
responseUrl: null,
headers: null,
sent: sendResult.sent,
status: ((_a = sendResult.gmailResponse) === null || _a === void 0 ? void 0 : _a.status) || null,
statusText: ((_b = sendResult.gmailResponse) === null || _b === void 0 ? void 0 : _b.statusText) || null,
responseUrl: ((_d = (_c = sendResult.gmailResponse) === null || _c === void 0 ? void 0 : _c.request) === null || _d === void 0 ? void 0 : _d.responseURL) || null,
message: sendResult.message,
gmailResponse: sendResult.gmailResponse || null,
};
}
const adjustedParams = Object.assign(Object.assign({}, params), { senderEmail });
return (0, sendEmail_1.sendEmail)(this.gmailClient, adjustedParams);
});

@@ -104,0 +145,0 @@ }

@@ -5,15 +5,12 @@ import { google } from 'googleapis';

senderEmail: string;
subject?: string;
encodedSubject?: string;
textMessage?: string;
htmlMessage?: string;
subject: string;
message: string;
}
export interface ISendEmailResponse {
status: boolean;
statusCode: any;
statusText: any;
responseUrl: any;
headers: any;
sent: boolean;
status: number | null;
statusText: string | null;
responseUrl: string | null;
message: string;
responseData: any | null;
gmailResponse: any | null;
}

@@ -34,1 +31,6 @@ export interface IInitializeClientParams {

}
export interface ISendEmailFunctionResponse {
sent: boolean;
message: string;
gmailResponse: any;
}

@@ -10,3 +10,3 @@ "use strict";

constructor() {
this._gmailSenderEmail = process.env.GMAIL_USER;
this._gmailSenderEmail = process.env.GMAIL_MAILER_SENDER_EMAIL;
}

@@ -26,4 +26,7 @@ /**

setGmailSenderEmail(email) {
if (email && !(0, isValidEmail_1.isValidEmail)(email)) {
throw new Error("The provided Gmail sender's email is invalid.");
if (email) {
const validation = (0, isValidEmail_1.isValidEmail)({ email });
if (!validation.status || !validation.result) {
throw new Error("The provided Gmail sender's email is invalid.");
}
}

@@ -30,0 +33,0 @@ this._gmailSenderEmail = email;

@@ -9,5 +9,11 @@ /**

*
* @param {string} email The email address to validate.
* @returns {boolean} True if the email address is valid, false otherwise.
* @param {{ email: string }} params An object containing the email address to validate.
* @returns {{ status: boolean, result: boolean | null }} Object containing the status of the operation
* and the result of the email validation.
*/
export declare function isValidEmail(email: string): boolean;
export declare function isValidEmail({ email }: {
email: string;
}): {
status: boolean;
result: boolean | null;
};

@@ -12,9 +12,20 @@ "use strict";

*
* @param {string} email The email address to validate.
* @returns {boolean} True if the email address is valid, false otherwise.
* @param {{ email: string }} params An object containing the email address to validate.
* @returns {{ status: boolean, result: boolean | null }} Object containing the status of the operation
* and the result of the email validation.
*/
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
function isValidEmail({ email }) {
let status = false;
let result = null;
try {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
result = emailRegex.test(email);
status = true; // Operation succeeded
}
catch (error) {
console.error("Error validating email:", error.message);
result = false; // Explicitly setting result to false in case of error
}
return { status, result };
}
exports.isValidEmail = isValidEmail;
{
"name": "gmail-node-mailer",
"version": "1.6.607",
"version": "1.7.01",
"description": "",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

# Gmail Node Mailer
The \`gmail-node-mailer\` package provides a streamlined way to send emails using the Gmail API within Node.js applications. This package simplifies the process of setting up the Gmail API client, validating email addresses, and sending emails. It also offers flexibility by allowing users to configure the Gmail service account and sender email dynamically.
Simplify your email sending process within Node.js applications with `gmail-node-mailer`. This lightweight package harnesses the power of the Gmail API to send emails effortlessly. Whether you're sending a quick notification or a detailed newsletter, `gmail-node-mailer` makes it straightforward.
## Features
## Quick Features
- Initialize the Gmail API client with service account credentials.
- Validate sender and recipient email addresses.
- Send emails with customizable sender, recipient, subject, and message content.
- Configure service account and sender email through utility functions.
- 🚀 Quick setup with service account credentials.
- 📧 Validate and send emails with ease.
- 🎨 Supports both plain text and HTML content.
- 🔧 Easy configuration for service accounts and sender emails.
## Getting Started
## Get Started in Seconds
### Installation
### 1. Install with NPM
To install the package, run the following command in your Node.js project directory:
Run the following in your project directory:
\`\`\`bash
```bash
npm install gmail-node-mailer
\`\`\`
```
### Usage
### 2. Streamline Email Notifications with Your Server Workflow
1. **Initialize the Gmail API Client**
`gmail-node-mailer` is designed to seamlessly integrate into your server setup, enabling you to send emails for various events such as server start/stop notifications, error alerts, and to manage subscription events like new subscriptions or renewals.
Before sending emails, you must initialize the Gmail API client with your service account credentials.
## Detailed Usage Guide
\`\`\`typescript
import { GmailMailer } from 'gmail-node-mailer';
### Server Start/Stop Notifications
const mailer = new GmailMailer();
Certainly! Here's the detailed portion you requested for the **Server Start/Stop Notifications** using `gmail-node-mailer`:
// Initialize with your service account credentials
await mailer.initializeClient({
gmailServiceAccountPath: '/path/to/service-account.json',
});
\`\`\`
### Server Start/Stop Notifications
2. **Send an Email**
Seamlessly notify about server start or stop events using `gmail-node-mailer`. Here's an example on how to set up and send these notifications:
After initializing the client, you can send emails by providing the sender, recipient, subject, and message.
```typescript
import { GmailMailer } from 'gmail-node-mailer';
\`\`\`typescript
const emailParams = {
senderEmail: 'your-email@gmail.com',
recipientEmail: 'recipient-email@gmail.com',
subject: 'Hello from Gmail Node Mailer',
message: 'This is a test email sent using the Gmail Node Mailer package.',
};
// Assuming global.gmailClient is declared somewhere globally accessible within your application.
declare global {
namespace NodeJS {
interface Global {
gmailClient: GmailMailer;
}
}
}
const response = await mailer.sendEmailWrapper(emailParams);
console.log(response.message);
\`\`\`
async function initializeMailer() {
const mailer = new GmailMailer();
await mailer.initializeClient({
gmailServiceAccountPath: './path/to/your-service-account.json',
});
// Setting the initialized mailer to a global variable
global.gmailClient = mailer;
}
## Configuration
async function notifyServerStatus(status: 'start' | 'stop') {
const message = status === 'start' ? 'Server is up and running.' : 'Server has been shut down.';
try {
await global.gmailClient.sendEmail({
senderEmail: "sender@example.com", // Or use process.env.GMAIL_MAILER_SENDER_EMAIL if configured
recipientEmail: 'admin@example.com',
subject: `Server ${status} Notification`,
message,
});
} catch (error) {
console.error('Error sending email:', error);
}
}
- **Service Account**: Set the path to your service account JSON file or directly provide the service account object.
- **Sender Email**: Configure the default sender email address.
// Initialize the GmailMailer client and then notify server status
initializeMailer().then(() => {
notifyServerStatus('start').catch(console.error);
});
## Utilities
// Further down in your server code, you can use global.gmailClient for other email sending purposes
```
This package includes utilities for validating email addresses, parsing service account files, and managing configuration settings.
This snippet demonstrates how to set up `gmail-node-mailer` for sending notifications related to server start and stop events. It involves initializing the `GmailMailer` client with the necessary service account credentials and then using it to send email notifications.
Certainly, here's a detailed example of how to handle new subscriptions and renewals with `gmail-node-mailer`. This example assumes you're integrating with a payment system like Stripe and want to send personalized emails upon new subscription sign-ups or subscription renewals.
## Contributing
```markdown
### Handling New Subscriptions and Renewals
Contributions, issues, and feature requests are welcome! Feel free to check [issues page](#).
Integrate subscription handling in your payment system to send personalized welcome emails or renewal confirmations. Utilizing `gmail-node-mailer`, you can automate the process of notifying customers about their subscription status, enhancing the overall customer experience. Below are examples for handling new subscriptions and renewals.
## License
#### New Subscription Welcome Emails
Distributed under the MIT License. See \`LICENSE\` for more information.
When a new customer subscribes, sending a welcome email is a great way to start your relationship. Here's how you can set this up:
```typescript
import { GmailMailer } from 'gmail-node-mailer';
export async function handleNewSubscription(customerEmail, subscriptionDetails) {
const mailer = new GmailMailer();
await mailer.initializeClient({
gmailServiceAccountPath: './path/to/your-service-account.json',
});
const htmlMessage = `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f0f0f0; }
.content { background-color: #fff; padding: 20px; }
h1 { color: #007bff; }
</style>
</head>
<body>
<div class="content">
<h1>Welcome to Your New Adventure!</h1>
<p>Dear Adventurer, thank you for joining us. Your journey starts now!</p>
<!-- Add more personalized content here -->
</div>
</body>
</html>
`;
await mailer.sendEmail({
senderEmail: process.env.GMAIL_MAILER_SENDER_EMAIL,
recipientEmail: customerEmail,
subject: '🎉 Welcome to Your New Adventure!',
message: htmlMessage,
});
}
```
#### Subscription Renewal Confirmations
Similarly, for subscription renewals, sending a confirmation email reaffirms the customer's value to your service. Here's a sample approach:
```typescript
// Assuming the GmailMailer is initialized similarly as in the new subscription example
export async function handleSubscriptionRenewal(customerEmail, renewalDetails) {
const htmlMessage = `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f0f0f0; }
.content { background-color: #fff; padding: 20px; }
h1 { color: #007bff; }
</style>
</head>
<body>
<div class="content">
<h1>Your Adventure Continues!</h1>
<p>Dear Adventurer, we're thrilled to have you with us for another year. Here's to more adventures together!</p>
<!-- Add renewal-specific content here -->
</div>
</body>
</html>
`;
// Use the initialized GmailMailer instance to send the email
await mailer.sendEmail({
senderEmail: process.env.GMAIL_MAILER_SENDER_EMAIL,
recipientEmail: customerEmail,
subject: '🎉 Thank You for Renewing Your Adventure!',
message: htmlMessage,
});
}
```
These examples showcase how to integrate `gmail-node-mailer` for sending dynamic, personalized emails for new subscriptions and renewals, enhancing your automated communication strategy.
## Advanced Initialization and Configuration
`gmail-node-mailer` offers a flexible and powerful way to initialize and configure your email sending capabilities. Here's a deep dive into customizing the initialization:
### Initializing with Service Account Credentials
Authenticate using a Gmail service account for secure email sending. To do this, you need to initialize the `GmailMailer` with your service account details. This can be done by either directly providing the service account details or specifying a file path to a JSON file containing these credentials. Here's how you can accomplish this:
```typescript
import { GmailMailer } from 'gmail-node-mailer';
const mailer = new GmailMailer();
// Initialize using direct service account details or a file path
await mailer.initializeClient({
gmailServiceAccount: {
client_email: 'your-service-account-email@your-project.iam.gserviceaccount.com',
private_key: '-----BEGIN PRIVATE KEY-----\n...your-private-key...\n-----END PRIVATE KEY-----\n'
},
// OR
gmailServiceAccountPath: './path/to/your-service-account.json',
});
```
### Configuring Sender Email
Specify and validate a default sender email address:
```typescript
import { emailConfig } from 'gmail-node-mailer/utils/emailConfig';
// Set and validate the Gmail sender's email
emailConfig.setGmailSenderEmail('your-email@gmail.com');
// Optionally, you could include a validation check to ensure the email is correctly formatted
// and meets specific criteria (this is a pseudo-code example for demonstration purposes)
if (!emailConfig.validateEmailFormat('your-email@gmail.com')) {
console.error('Email format is invalid. Please use a valid Gmail address.');
} else {
console.log('Sender email configured successfully.');
}
```
### example sendEmail function response -->
```typescript
{
sendMailResult: {
sent: true,
status: 200,
statusText: 'OK',
responseUrl: 'https://gmail.googleapis.com/gmail/v1/users/me/messages/send',
message: 'Email successfully sent to waleed@glitchgaming.us.',
gmailResponse: {
config: [Object],
data: [Object],
headers: [Object],
status: 200,
statusText: 'OK',
request: [Object]
}
}
}
```
## Effortless Email Composition with Auto-Detection
When crafting emails, `gmail-node-mailer` simplifies your workflow by auto-detecting email formatting and subject encoding.
### Subject Auto-Encoding
Automatically encodes the subject line ensuring compatibility across all email clients.
### HTML or Text Message Auto-Detection
Write your message in either format, and `gmail-node-mailer` will handle the rest, ensuring it's correctly formatted.
## Environment Configuration for `gmail-node-mailer`
To seamlessly integrate `gmail-node-mailer` into your Node.js project, configure the necessary environment variables.
### Required Environment Variables
- **`GMAIL_MAILER_SENDER_EMAIL`**: Specifies the sender's email address.
### Optional Environment Variables for Service Account Configuration
- **`GMAIL_MAILER_SERVICE_ACCOUNT_PATH`**: Used primarily in development environments, this variable points to the local JSON file containing your service account credentials.
```plaintext
GMAIL_MAILER_SERVICE_ACCOUNT_PATH=./private/somnus_gmail_service_account.json
```
Ensure the path is correctly specified relative to the root of your project.
- **`GMAIL_MAILER_SERVICE_ACCOUNT`**: In production environments, or when direct file access is restricted, you may opt to provide your service account credentials as a JSON string directly within an environment variable.
```plaintext
GMAIL_MAILER_SERVICE_ACCOUNT={"type":"service_account","project_id":"...","private_key_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n","client_email":"....iam.gserviceaccount.com","client_id":"...","auth_uri":"...","token_uri":"...","auth_provider_x509_cert_url":"...","client_x509_cert_url":"...","universe_domain":"googleapis.com"}
```
Note: Ensure special characters in the JSON (like newlines in the private key) are properly escaped. This example simplifies the actual process for readability; typically, you'll need to handle escaping or format the JSON appropriately.
### Choosing the Right Configuration
- For **development**, using the `GMAIL_MAILER_SERVICE_ACCOUNT_PATH` variable to reference a local file is often more convenient.
- For **production**, embedding the service account credentials directly in `GMAIL_MAILER_SERVICE_ACCOUNT` facilitates deployment in environments where file access may be limited.
By leveraging these features, `gmail-node-mailer` ensures that sending emails through your Node.js applications is not only powerful but also incredibly easy and intuitive.

@@ -5,8 +5,8 @@ import { isValidEmail } from '../utils/isValidEmail';

test('should return true for a valid email', () => {
expect(isValidEmail('test@example.com')).toBe(true);
expect(isValidEmail({email:'test@example.com'}).result).toBe(true);
});
test('should return false for an invalid email', () => {
expect(isValidEmail('testexample.com')).toBe(false);
expect(isValidEmail({email:'testexample.com'}).result).toBe(false);
});
});
import { gmail_v1 } from 'googleapis';
import { ISendEmailParams, ISendEmailResponse } from '../types';
import { ISendEmailParams, ISendEmailFunctionResponse } from '../types';
import { isSubjectMimeEncoded } from '../utils/isSubjectMimeEncoded';
import { encodeSubject } from '../utils/encodeSubject';
import { isHtmlMessage } from '../utils/isHtmlMessage';
/**
* Sends an email using the Gmail API client, supporting both HTML and plain text content.
* Sends an email using the Gmail API client, supporting both HTML and plain text content. It automatically
* MIME encodes the subject if it isn't already and determines whether the message content is HTML or plain text
* to format the email appropriately.
*
* @param {gmail_v1.Gmail} gmailClient The Gmail API client instance.
* @param {ISendEmailParams} params Parameters required for sending the email, including both text and HTML versions of the message.
* @returns {Promise<ISendEmailResponse>} The result of the email sending operation.
* @param {ISendEmailParams} params Parameters required for sending the email, including sender, recipient, subject, and message content.
* @returns {Promise<ISendEmailFunctionResponse>} The result of the email sending operation, including whether the email was sent successfully, the status message, and the raw Gmail API response.
*/
export async function sendEmail(
gmailClient: gmail_v1.Gmail,
{ senderEmail, recipientEmail, subject, encodedSubject, textMessage, htmlMessage }: ISendEmailParams
): Promise<ISendEmailResponse> {
if (!gmailClient) {
return {
status: false,
statusCode: null,
statusText: null,
responseUrl: null,
message: 'The Gmail client has not been initialized. Please call initializeClient first.',
responseData: null,
headers: null,
};
}
// Check for subject
if (!subject && !encodedSubject) {
return {
status: false,
statusCode: null,
statusText: null,
responseUrl: null,
message: 'A subject or encodedSubject must be provided.',
responseData: null,
headers: null,
};
export async function sendEmailFunction(gmailClient: gmail_v1.Gmail, { senderEmail, recipientEmail, subject, message }: ISendEmailParams): Promise<ISendEmailFunctionResponse> {
let finalSubject = subject; // Initialize finalSubject with the original subject
const encodedCheck = isSubjectMimeEncoded({ subject });
if (!encodedCheck.result) {
// If subject is not MIME encoded, encode it
const { status, result } = encodeSubject({ subject });
if (status) {
finalSubject = result;
}
}
// Use subject if both are provided
const finalSubject = subject || encodedSubject;
// Determine if the message is HTML or plain text
const htmlCheck = isHtmlMessage({ message });
let mimeMessage = `From: ${senderEmail}\r\nTo: ${recipientEmail}\r\nSubject: ${finalSubject}\r\n`;
// Check for message content
if (!textMessage && !htmlMessage) {
return {
status: false,
statusCode: null,
statusText: null,
responseUrl: null,
message: 'At least one of textMessage or htmlMessage must be provided.',
responseData: null,
headers: null,
};
// Construct MIME message based on HTML check result
const boundary = "----=_NextPart_" + Math.random().toString(36).substr(2, 9);
if (htmlCheck.result) {
mimeMessage += `Content-Type: multipart/alternative; boundary=${boundary}\r\n\r\n` +
`--${boundary}\r\n` +
`Content-Type: text/html; charset=UTF-8\r\n\r\n` +
`${message}\r\n` +
`--${boundary}--`;
} else {
mimeMessage += `Content-Type: text/plain; charset=UTF-8\r\n\r\n${message}`;
}
// Generate a boundary string for the MIME message
const boundary = "----=_NextPart_" + Math.random().toString(36).substr(2, 9);
// Construct the MIME message with both plain text and HTML parts
const mimeMessage = [
`From: ${senderEmail}`,
`To: ${recipientEmail}`,
`Subject: ${finalSubject}`, // Use the finalSubject here
`Content-Type: multipart/alternative; boundary=${boundary}`,
"",
`--${boundary}`,
"Content-Type: text/plain; charset=UTF-8",
"",
textMessage || " ", // Provide a fallback if textMessage is not provided
`--${boundary}`,
"Content-Type: text/html; charset=UTF-8",
"",
htmlMessage || "<p></p>", // Provide a minimal HTML structure as a fallback if htmlMessage is not provided
`--${boundary}--`,
].join("\r\n");
const encodedEmail = Buffer.from(mimeMessage, 'utf-8').toString('base64').replace(/\+/g, '-').replace(/\//g, '_');
try {
const response = await gmailClient.users.messages.send({
const gmailResponse = await gmailClient.users.messages.send({
userId: 'me',

@@ -85,34 +53,12 @@ requestBody: { raw: encodedEmail },

if (response.status < 200 || response.status >= 300) {
return {
status: false,
statusCode: response.status,
statusText: response.statusText,
responseUrl: response.request.responseURL,
message: `Failed to send email. Status: ${response.status}`,
responseData: response.data,
headers: response.headers,
};
}
return {
status: true,
statusCode: response.status,
statusText: response.statusText,
responseUrl: response.request.responseURL,
message: `Email successfully sent to ${recipientEmail}.`,
responseData: response.data,
headers: response.headers,
sent: gmailResponse.status >= 200 && gmailResponse.status < 300,
message: gmailResponse.status >= 200 && gmailResponse.status < 300 ?
`Email successfully sent to ${recipientEmail}.` :
`Failed to send email. Status: ${gmailResponse.status}`,
gmailResponse: gmailResponse,
};
} catch (error: any) {
return {
status: true,
statusCode: null,
statusText: null,
responseUrl: null,
message: `An error occurred while sending the email: ${error.message}`,
responseData: null,
headers: null,
};
return { sent: false, message: `An error occurred while sending the email: ${error.message}`, gmailResponse: null };
}
}
import { google, gmail_v1 } from 'googleapis';
import { sendEmail as sendEmailFunction } from './functions/sendEmail';
import { sendEmailFunction } from './functions/sendEmail';
import { isValidEmail } from './utils/isValidEmail';

@@ -7,5 +7,7 @@ import { parseServiceAccountFile } from './utils/parseServiceAccountFile';

import { gmailServiceAccountConfig } from './utils/gmailServiceAccountConfig';
import { generateErrorResponse } from './utils/generateErrorResponse';
import {
IInitializeClientParams,
IInitializeClientResult,
ISendEmailFunctionResponse,
ISendEmailParams,

@@ -23,8 +25,28 @@ ISendEmailResponse

/**
* Initializes the Gmail API client with provided configuration.
* Validates the Gmail sender email and uses service account credentials for authentication.
* Initializes the Gmail API client using the provided or environment-based configuration. This method validates the
* Gmail sender's email address and authenticates using service account credentials. It supports multiple ways to provide
* these credentials: directly via parameters, loaded from a file path, or parsed from an environment variable.
*
* @param {IInitializeClientParams} config - Configuration for Gmail client initialization.
* @returns {Promise<IInitializeClientResult>} - Result of initialization attempt.
* The service account credentials can be provided in several ways:
* - Directly via the method parameters.
* - By specifying a file path to load the credentials from (`gmailServiceAccountPath`).
* - Through the `GMAIL_MAILER_SERVICE_ACCOUNT` environment variable, which should contain the JSON representation
* of the service account credentials.
*
* If the credentials are not directly provided, the method first attempts to load them from the specified file path.
* If no valid path is provided or if the file does not contain valid credentials, it then attempts to parse the credentials
* from the `GMAIL_MAILER_SERVICE_ACCOUNT` environment variable.
*
* This flexible initialization approach allows the GmailMailer to be configured seamlessly across different environments,
* making it highly suitable for both development and production use. For instance, in development, you can provide the
* `GMAIL_MAILER_SERVICE_ACCOUNT_PATH` environment variable pointing to a local JSON file with your service account credentials.
* In production environments, such as on a Digital Ocean server or other cloud environments where direct file access may be
* restricted or inconvenient, you can directly provide the service account credentials as a JSON string via the
* `GMAIL_MAILER_SERVICE_ACCOUNT` environment variable. This design ensures that the package automatically works in both environments
* without the need for code changes, simplifying deployment and integration.
*
* @param {IInitializeClientParams} config - Configuration for Gmail client initialization, including service account details and sender email.
* @returns {Promise<IInitializeClientResult>} - The result of the initialization attempt, including the status, initialized Gmail client instance, and any error messages.
*/
async initializeClient({

@@ -36,6 +58,11 @@ gmailServiceAccount = gmailServiceAccountConfig.getServiceAccount(),

try {
if (!gmailSenderEmail || !isValidEmail(gmailSenderEmail)) {
if (!gmailSenderEmail || !isValidEmail({ email: gmailSenderEmail }).result) {
throw new Error("Invalid or missing Gmail sender's email.");
}
// If gmailServiceAccountPath is not provided, use the environment variable
if (!gmailServiceAccountPath) {
gmailServiceAccountPath = process.env.GMAIL_MAILER_SERVICE_ACCOUNT_PATH;
}
if (!gmailServiceAccount && gmailServiceAccountPath) {

@@ -46,5 +73,14 @@ const serviceAccountResult = await parseServiceAccountFile({ filePath: gmailServiceAccountPath });

}
gmailServiceAccountConfig.setServiceAccount(serviceAccountResult.serviceAccount);
gmailServiceAccount = serviceAccountResult.serviceAccount; // Set the gmailServiceAccount with the loaded service account
}
// Check for service account JSON in GMAIL_MAILER_SERVICE_ACCOUNT environment variable as a fallback
if (!gmailServiceAccount && process.env.GMAIL_MAILER_SERVICE_ACCOUNT) {
try {
gmailServiceAccount = JSON.parse(process.env.GMAIL_MAILER_SERVICE_ACCOUNT);
} catch (error) {
throw new Error("Failed to parse service account from GMAIL_MAILER_SERVICE_ACCOUNT environment variable.");
}
}
if (!gmailServiceAccount) {

@@ -80,18 +116,11 @@ throw new Error("Service account configuration is missing.");

/**
* Sends an email using the initialized Gmail API client. Validates sender email if not provided.
*
* @param {ISendEmailParams} params - Email sending parameters.
* @returns {Promise<ISendEmailResponse>} - Result of the email sending operation.
*/
* Sends an email using the initialized Gmail API client. It validates the sender email, ensures a subject
* is provided, and verifies that the message content is present before proceeding.
*
* @param {ISendEmailParams} params Parameters for sending the email, including recipient, sender, subject, and message.
* @returns {Promise<ISendEmailResponse>} The result of the email sending operation, including status and any response details.
*/
async sendEmail(params: ISendEmailParams): Promise<ISendEmailResponse> {
if (!this.gmailClient) {
return {
status: false,
message: 'Gmail client not initialized. Please initialize before sending emails.',
responseData: null,
statusCode: null,
statusText: null,
responseUrl: null,
headers: null,
};
return generateErrorResponse({ message: 'The Gmail client has not been initialized. Please call initializeClient first.' });
}

@@ -101,16 +130,34 @@

if (!senderEmail) {
return generateErrorResponse({ message: 'Sender email not configured. Please provide a sender email.' });
}
if (!params.subject) {
return generateErrorResponse({ message: 'A subject (text or encoded) must be provided.' });
}
if (!params.message) {
return generateErrorResponse({ message: 'At least one of textMessage or htmlMessage must be provided.' });
}
const adjustedParams = { ...params, senderEmail };
// Assuming sendEmailFunction is properly imported and utilized
const sendResult: ISendEmailFunctionResponse = await sendEmailFunction(this.gmailClient, adjustedParams);
if (!sendResult.sent) {
// Handling failure from the sendEmail function
return generateErrorResponse({ message: sendResult.message });
} else {
// Handling success from the sendEmail function
return {
status: false,
message: 'Sender email not configured. Please provide a sender email.',
responseData: null,
statusCode: null,
statusText: null,
responseUrl: null,
headers: null,
sent: sendResult.sent,
status: sendResult.gmailResponse?.status || null,
statusText: sendResult.gmailResponse?.statusText || null,
responseUrl: sendResult.gmailResponse?.request?.responseURL || null,
message: sendResult.message,
gmailResponse: sendResult.gmailResponse || null,
};
}
}
const adjustedParams = { ...params, senderEmail };
return sendEmailFunction(this.gmailClient, adjustedParams);
}
}
}

@@ -6,16 +6,13 @@ import { google } from 'googleapis';

senderEmail: string;
subject?: string;
encodedSubject?: string;
textMessage?: string;
htmlMessage?: string;
subject: string;
message: string;
}
export interface ISendEmailResponse {
status: boolean;
statusCode: any
statusText: any;
responseUrl: any;
headers:any;
sent: boolean;
status: number | null;
statusText: string | null;
responseUrl: string | null;
message: string;
responseData: any | null;
gmailResponse: any | null;
};

@@ -38,1 +35,7 @@

}
export interface ISendEmailFunctionResponse {
sent: boolean;
message: string;
gmailResponse: any;
}

@@ -7,3 +7,3 @@ import { isValidEmail } from './isValidEmail';

class EmailConfig {
private _gmailSenderEmail: string | undefined = process.env.GMAIL_USER;
private _gmailSenderEmail: string | undefined = process.env.GMAIL_MAILER_SENDER_EMAIL;

@@ -24,4 +24,7 @@ /**

setGmailSenderEmail(email: string | undefined) {
if (email && !isValidEmail(email)) {
throw new Error("The provided Gmail sender's email is invalid.");
if (email) {
const validation = isValidEmail({ email });
if (!validation.status || !validation.result) {
throw new Error("The provided Gmail sender's email is invalid.");
}
}

@@ -32,2 +35,2 @@ this._gmailSenderEmail = email;

export const emailConfig = new EmailConfig();
export const emailConfig = new EmailConfig();

@@ -9,8 +9,18 @@ /**

*
* @param {string} email The email address to validate.
* @returns {boolean} True if the email address is valid, false otherwise.
* @param {{ email: string }} params An object containing the email address to validate.
* @returns {{ status: boolean, result: boolean | null }} Object containing the status of the operation
* and the result of the email validation.
*/
export function isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
export function isValidEmail({ email }: { email: string }): { status: boolean, result: boolean | null } {
let status = false;
let result: boolean | null = null;
try {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
result = emailRegex.test(email);
status = true; // Operation succeeded
} catch (error: any) {
console.error("Error validating email:", error.message);
result = false; // Explicitly setting result to false in case of error
}
return { status, result };
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc