Skip to content

Commit

Permalink
Merge pull request #72 from atlp-rwanda/ft-mail-microservice-#187658871
Browse files Browse the repository at this point in the history
#187658871 separate our mail service from the rest of the system
  • Loading branch information
teerenzo authored May 30, 2024
2 parents 1e8164b + a33f897 commit adc04b1
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 8 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"devDependencies": {
"@babel/helper-compilation-targets": "^7.23.6",
"@eslint/js": "^9.1.1",
"@types/aws-sdk": "^2.7.0",
"@types/bcryptjs": "^2.4.6",
"@types/cors": "^2.8.17",
"@types/dotenv": "^8.2.0",
Expand Down
44 changes: 44 additions & 0 deletions src/sequelize/migrations/20240527133340-create-failed-email.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('failedEmails', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER
},
email: {
type: Sequelize.STRING
},
subject: {
type: Sequelize.STRING
},
body: {
type: Sequelize.TEXT
},
attempts: {
type: Sequelize.INTEGER
},
lastAttempted: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('failedEmails');
}
};
59 changes: 59 additions & 0 deletions src/sequelize/models/failedemail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { DataTypes, Model } from 'sequelize';
import sequelize from '../../config/dbConnection';

interface FailedEmailAttributes {
id: number;
userId: number;
email: string;
subject: string;
body: string;
attempts: number;
lastAttempted: Date;
}

class FailedEmail extends Model<FailedEmailAttributes> implements FailedEmailAttributes {
id!: number;
userId!: number;
email!: string;
subject!: string;
body!: string;
attempts!: number;
lastAttempted!: Date;
}

FailedEmail.init({
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
subject: {
type: DataTypes.STRING,
allowNull: false,
},
body: {
type: DataTypes.TEXT,
allowNull: false,
},
attempts: {
type: DataTypes.INTEGER,
defaultValue: 0,
},
lastAttempted: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
}, {
sequelize,
modelName: 'failedEmails',
});

export default FailedEmail;
59 changes: 51 additions & 8 deletions src/services/mail.service.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
import FailedEmail from "../sequelize/models/failedemail";
import { IUser } from "../types";
import { env } from "../utils/env";
import transporter from "../utils/transporter";
import axios from "axios";
import cron from "node-cron";

export const sendEmailService = async (user: IUser, subject: string, template: any, token?: number) => {
try {
const mailOptions = {
from: env.smtp_user,
const apiEndpoint: any = process.env.URL_SEND_EMAIL;
const emailData = {
to: user.email,
subject: subject,
html: template,
body: template,
};


const info = await transporter.sendMail(mailOptions);
//@ts-ignore

const response = await axios.post(apiEndpoint, emailData);
} catch (error: any) {
throw new Error(error.message);
try {
const rs = await FailedEmail.create({
// @ts-ignore
userId: user.id,
email: user.email,
subject: subject,
body: template,
attempts: 1,
lastAttempted: new Date(),
});
} catch (error: any) {
throw new Error(error.message);
}
throw error;
}
};

export const sendNotification = async (email: string | undefined, subject: string, template: any) => {
try {
const mailOptions = {
Expand All @@ -33,3 +48,31 @@ export const sendNotification = async (email: string | undefined, subject: strin
throw new Error(error.message);
}
};

const retryFailedEmail = async () => {
const allFailedEmail = await FailedEmail.findAll();

for (const email of allFailedEmail) {
try {
const apiEndpoint: any = process.env.URL_SEND_EMAIL;

const failedEmailData = {
to: email.dataValues.email,
subject: email.dataValues.subject,
body: email.dataValues.body,
};

const response = await axios.post(apiEndpoint, failedEmailData);
await email.destroy();
} catch (error: any) {
email.attempts = email.dataValues.attempts + 1;
email.dataValues.lastAttempted = new Date();
await email.save();
throw new Error(error.message);
}
}
};

cron.schedule("0 * * * *", () => {
retryFailedEmail();
});

0 comments on commit adc04b1

Please sign in to comment.