fix(mail.service): use sendgrid api instead of nodemailer for better deliverability
This commit is contained in:
parent
e96b090904
commit
9df12194bf
|
@ -28,8 +28,6 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
|
|||
/>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="initial-scale=1, width=device-width" />
|
||||
|
||||
<script src="/__ENV.js" />
|
||||
</Head>
|
||||
|
||||
<ReduxProvider store={store}>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import { NextPage } from 'next';
|
||||
import NextDocument, { DocumentContext, Head, Html, Main, NextScript } from 'next/document';
|
||||
|
||||
const Document: NextPage = () => (
|
||||
<Html>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
|
||||
<script src="/__ENV.js" />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
|
||||
Document.getInitialProps = async (ctx: DocumentContext) => {
|
||||
const initialProps = await NextDocument.getInitialProps(ctx);
|
||||
|
||||
return initialProps;
|
||||
};
|
||||
|
||||
export default Document;
|
|
@ -188,6 +188,8 @@ importers:
|
|||
'@nestjs/serve-static': ^2.2.2
|
||||
'@nestjs/typeorm': ^8.0.3
|
||||
'@reactive-resume/schema': workspace:*
|
||||
'@sendgrid/mail': ^7.6.1
|
||||
'@types/bcrypt': ^5.0.0
|
||||
'@types/express': ^4.17.13
|
||||
'@types/multer': ^1.4.7
|
||||
'@types/node': ^17.0.21
|
||||
|
@ -238,6 +240,7 @@ importers:
|
|||
'@nestjs/schedule': 1.0.2_1ce925e2290a1cea9e3700e8a60baeb5
|
||||
'@nestjs/serve-static': 2.2.2_31e7036b193d6d3c9cadab18cbb4af84
|
||||
'@nestjs/typeorm': 8.0.3_a8e966c473b8cac7d0f44522ae3cdd56
|
||||
'@sendgrid/mail': 7.6.1
|
||||
'@types/passport': 1.0.7
|
||||
bcrypt: 5.0.1
|
||||
cache-manager: 3.6.0
|
||||
|
@ -269,6 +272,7 @@ importers:
|
|||
'@nestjs/cli': 8.2.2
|
||||
'@nestjs/schematics': 8.0.7_typescript@4.5.5
|
||||
'@reactive-resume/schema': link:../schema
|
||||
'@types/bcrypt': 5.0.0
|
||||
'@types/express': 4.17.13
|
||||
'@types/multer': 1.4.7
|
||||
'@types/node': 17.0.21
|
||||
|
@ -1885,6 +1889,33 @@ packages:
|
|||
resolution: {integrity: sha512-JLo+Y592QzIE+q7Dl2pMUtt4q8SKYI5jDrZxrozEQxnGVOyYE+GWK9eLkwTaeN9DDctlaRAQ3TBmzZ1qdLE30A==}
|
||||
dev: true
|
||||
|
||||
/@sendgrid/client/7.6.1:
|
||||
resolution: {integrity: sha512-q4U5OhcbJjs+lLVv/LhZSc28feiVCFMgvG9aYcRI5X4tKArnrrGDWb5HMITR9vaAtX42TXhyPFjHr1fk/Q1loQ==}
|
||||
engines: {node: 6.* || 8.* || >=10.*}
|
||||
dependencies:
|
||||
'@sendgrid/helpers': 7.6.0
|
||||
axios: 0.21.4
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/@sendgrid/helpers/7.6.0:
|
||||
resolution: {integrity: sha512-0uWD+HSXLl4Z/X3cN+UMQC20RE7xwAACgppnfjDyvKG0KvJcUgDGz7HDdQkiMUdcVWfmyk6zKSg7XKfKzBjTwA==}
|
||||
engines: {node: '>= 6.0.0'}
|
||||
dependencies:
|
||||
deepmerge: 4.2.2
|
||||
dev: false
|
||||
|
||||
/@sendgrid/mail/7.6.1:
|
||||
resolution: {integrity: sha512-F+HXpDLIU4PGZyZznOiFLDGJDwLn2qh7/wD5MvwurrldDx5DaGQHrYBKHopceOl15FVuq9ElU9VIxQJF8SMvTg==}
|
||||
engines: {node: 6.* || 8.* || >=10.*}
|
||||
dependencies:
|
||||
'@sendgrid/client': 7.6.1
|
||||
'@sendgrid/helpers': 7.6.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/@sideway/address/4.1.3:
|
||||
resolution: {integrity: sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==}
|
||||
dependencies:
|
||||
|
@ -1919,6 +1950,12 @@ packages:
|
|||
resolution: {integrity: sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==}
|
||||
dev: true
|
||||
|
||||
/@types/bcrypt/5.0.0:
|
||||
resolution: {integrity: sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==}
|
||||
dependencies:
|
||||
'@types/node': 17.0.21
|
||||
dev: true
|
||||
|
||||
/@types/body-parser/1.19.2:
|
||||
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
|
||||
dependencies:
|
||||
|
@ -2704,6 +2741,14 @@ packages:
|
|||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/axios/0.21.4:
|
||||
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
||||
dependencies:
|
||||
follow-redirects: 1.14.9
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/axios/0.26.0:
|
||||
resolution: {integrity: sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==}
|
||||
dependencies:
|
||||
|
@ -3509,7 +3554,6 @@ packages:
|
|||
/deepmerge/4.2.2:
|
||||
resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/defaults/1.0.3:
|
||||
resolution: {integrity: sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"@nestjs/schedule": "^1.0.2",
|
||||
"@nestjs/serve-static": "^2.2.2",
|
||||
"@nestjs/typeorm": "^8.0.3",
|
||||
"@sendgrid/mail": "^7.6.1",
|
||||
"@types/passport": "^1.0.7",
|
||||
"bcrypt": "^5.0.1",
|
||||
"cache-manager": "^3.6.0",
|
||||
|
@ -30,13 +31,11 @@
|
|||
"csvtojson": "^2.0.10",
|
||||
"dayjs": "^1.10.8",
|
||||
"googleapis": "^95.0.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"joi": "^17.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"multer": "^1.4.4",
|
||||
"nanoid": "^3.3.1",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"nodemailer": "^6.7.2",
|
||||
"passport": "^0.5.2",
|
||||
"passport-jwt": "^4.0.0",
|
||||
"passport-local": "^1.0.0",
|
||||
|
@ -52,6 +51,8 @@
|
|||
"devDependencies": {
|
||||
"@nestjs/cli": "^8.2.2",
|
||||
"@nestjs/schematics": "^8.0.7",
|
||||
"@reactive-resume/schema": "workspace:*",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^17.0.21",
|
||||
|
@ -62,7 +63,6 @@
|
|||
"ts-node": "^10.7.0",
|
||||
"tsconfig-paths": "^3.13.0",
|
||||
"typescript": "<4.6.0",
|
||||
"webpack": "^5.70.0",
|
||||
"@reactive-resume/schema": "workspace:*"
|
||||
"webpack": "^5.70.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,288 +0,0 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset='utf-8' />
|
||||
<meta http-equiv='x-ua-compatible' content='ie=edge' />
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1' />
|
||||
|
||||
<title>Reset Your Password</title>
|
||||
|
||||
<style type='text/css'>
|
||||
@media screen { @font-face { font-family: "Source Sans Pro"; font-style: normal; font-weight: 400; src:
|
||||
local("Source Sans Pro Regular"), local("SourceSansPro-Regular"),
|
||||
url(https://fonts.gstatic.com/s/sourcesanspro/v10/ODelI1aHBYDBqgeIAH2zlBM0YzuT7MdOe03otPbuUS0.woff)
|
||||
format("woff"); } @font-face { font-family: "Source Sans Pro"; font-style: normal; font-weight: 700; src:
|
||||
local("Source Sans Pro Bold"), local("SourceSansPro-Bold"),
|
||||
url(https://fonts.gstatic.com/s/sourcesanspro/v10/toadOcfmlt9b38dHJxOBGFkQc6VGVFSmCnC_l7QZG60.woff)
|
||||
format("woff"); } } body, table, td, a { -ms-text-size-adjust: 100%; /* 1 */ -webkit-text-size-adjust: 100%; /* 2
|
||||
*/ } /** * Remove extra space added to tables and cells in Outlook. */ table, td { mso-table-rspace: 0pt;
|
||||
mso-table-lspace: 0pt; } /** * Better fluid images in Internet Explorer. */ img { -ms-interpolation-mode: bicubic;
|
||||
} /** * Remove blue links for iOS devices. */ a[x-apple-data-detectors] { font-family: inherit !important;
|
||||
font-size: inherit !important; font-weight: inherit !important; line-height: inherit !important; color: inherit
|
||||
!important; text-decoration: none !important; } /** * Fix centering issues in Android 4.4. */ div[style*="margin:
|
||||
16px 0; "] { margin: 0 !important; } body { width: 100% !important; height: 100% !important; padding: 0
|
||||
!important; margin: 0 !important; } /** * Collapse table borders to avoid space between cells. */ table {
|
||||
border-collapse: collapse !important; } a { color: #1a82e2; } img { height: auto; line-height: 100%;
|
||||
text-decoration: none; border: 0; outline: none; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style='background-color: #e9ecef'>
|
||||
<!-- start preheader -->
|
||||
<div
|
||||
class='preheader'
|
||||
style='
|
||||
display: none;
|
||||
max-width: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
font-size: 1px;
|
||||
line-height: 1px;
|
||||
color: #fff;
|
||||
opacity: 0;
|
||||
'
|
||||
>
|
||||
Inside this email, you will find a unique link to reset your password. Do not share this email with anyone as your
|
||||
account may become compromised.
|
||||
</div>
|
||||
<!-- end preheader -->
|
||||
|
||||
<!-- start body -->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%'>
|
||||
<!-- start logo -->
|
||||
<tr>
|
||||
<td align='center' bgcolor='#e9ecef'>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600">
|
||||
<tr>
|
||||
<td align="center" valign="top" width="600">
|
||||
<![endif]-->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%' style='max-width: 600px'>
|
||||
<tr>
|
||||
<td align='center' valign='top' style='padding: 36px 24px'>
|
||||
<a href='https://rxresu.me/' target='_blank' style='display: inline-block'>
|
||||
<img
|
||||
src='https://i.imgur.com/pc8Ingg.png'
|
||||
alt='Reactive Resume Logo'
|
||||
border='0'
|
||||
width='128'
|
||||
style='
|
||||
display: block;
|
||||
width: 128px;
|
||||
max-width: 128px;
|
||||
min-width: 128px;
|
||||
'
|
||||
/>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end logo -->
|
||||
|
||||
<!-- start hero -->
|
||||
<tr>
|
||||
<td align='center' bgcolor='#e9ecef'>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600">
|
||||
<tr>
|
||||
<td align="center" valign="top" width="600">
|
||||
<![endif]-->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%' style='max-width: 600px'>
|
||||
<tr>
|
||||
<td
|
||||
align='left'
|
||||
bgcolor='#ffffff'
|
||||
style="
|
||||
padding: 36px 24px 0;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
border-top: 3px solid #d4dadf;
|
||||
"
|
||||
>
|
||||
<h1
|
||||
style='
|
||||
margin: 0;
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -1px;
|
||||
line-height: 48px;
|
||||
'
|
||||
>
|
||||
Hello,
|
||||
{{name}}!
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end hero -->
|
||||
|
||||
<!-- start copy block -->
|
||||
<tr>
|
||||
<td align='center' bgcolor='#e9ecef'>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600">
|
||||
<tr>
|
||||
<td align="center" valign="top" width="600">
|
||||
<![endif]-->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%' style='max-width: 600px'>
|
||||
<!-- start copy -->
|
||||
<tr>
|
||||
<td
|
||||
align='left'
|
||||
bgcolor='#ffffff'
|
||||
style="
|
||||
padding: 24px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
"
|
||||
>
|
||||
<p style='margin: 0'>
|
||||
Tap the button below to reset your account password. If you didn't request a new password, you can
|
||||
safely delete this email.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end copy -->
|
||||
|
||||
<!-- start button -->
|
||||
<tr>
|
||||
<td align='left' bgcolor='#ffffff'>
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%'>
|
||||
<tr>
|
||||
<td align='center' bgcolor='#ffffff' style='padding: 12px'>
|
||||
<table border='0' cellpadding='0' cellspacing='0'>
|
||||
<tr>
|
||||
<td align='center' bgcolor='#1a82e2' style='border-radius: 6px'>
|
||||
<a
|
||||
href='{{url}}'
|
||||
target='_blank'
|
||||
style="
|
||||
display: inline-block;
|
||||
padding: 16px 36px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial,
|
||||
sans-serif;
|
||||
font-size: 16px;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
border-radius: 6px;
|
||||
"
|
||||
>Reset Your Password</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end button -->
|
||||
|
||||
<!-- start copy -->
|
||||
<tr>
|
||||
<td
|
||||
align='left'
|
||||
bgcolor='#ffffff'
|
||||
style="
|
||||
padding: 24px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
"
|
||||
>
|
||||
<p style='margin: 0'>
|
||||
If that doesn't work, copy and paste the following link in your browser:
|
||||
</p>
|
||||
<p style='margin: 0'>
|
||||
<a href='{{url}}' target='_blank'>{{url}}</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end copy -->
|
||||
|
||||
<!-- start copy -->
|
||||
<tr>
|
||||
<td
|
||||
align='left'
|
||||
bgcolor='#ffffff'
|
||||
style="
|
||||
padding: 24px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
border-bottom: 3px solid #d4dadf;
|
||||
"
|
||||
>
|
||||
<p style='margin: 0'>
|
||||
Cheers,<br />
|
||||
<a href='https://www.amruthpillai.com/'>Amruth Pillai</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end copy -->
|
||||
</table>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end copy block -->
|
||||
|
||||
<!-- start footer -->
|
||||
<tr>
|
||||
<td align='center' bgcolor='#e9ecef' style='padding: 24px'>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600">
|
||||
<tr>
|
||||
<td align="center" valign="top" width="600">
|
||||
<![endif]-->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%' style='max-width: 600px'>
|
||||
<!-- start permission -->
|
||||
<tr>
|
||||
<td
|
||||
align='center'
|
||||
bgcolor='#e9ecef'
|
||||
style="
|
||||
padding: 12px 24px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #666;
|
||||
"
|
||||
>
|
||||
<p style='margin: 0'>
|
||||
You received this email because we received a request for resetting the password for your account. If
|
||||
you didn't request a password reset you can safely delete this email.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end permission -->
|
||||
</table>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end footer -->
|
||||
</table>
|
||||
<!-- end body -->
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -2,7 +2,7 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
|||
import { ConfigService } from '@nestjs/config';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { google } from 'googleapis';
|
||||
|
||||
import { PostgresErrorCode } from '@/database/errorCodes.enum';
|
||||
|
|
|
@ -6,7 +6,7 @@ import appConfig from './app.config';
|
|||
import authConfig from './auth.config';
|
||||
import databaseConfig from './database.config';
|
||||
import googleConfig from './google.config';
|
||||
import mailConfig from './mail.config';
|
||||
import sendgridConfig from './sendgrid.config';
|
||||
|
||||
const validationSchema = Joi.object({
|
||||
// App
|
||||
|
@ -31,22 +31,19 @@ const validationSchema = Joi.object({
|
|||
JWT_SECRET: Joi.string().required(),
|
||||
JWT_EXPIRY_TIME: Joi.number().required(),
|
||||
|
||||
// Mail
|
||||
MAIL_HOST: Joi.string().allow(''),
|
||||
MAIL_PORT: Joi.number().default(465),
|
||||
MAIL_USERNAME: Joi.string().allow(''),
|
||||
MAIL_PASSWORD: Joi.string().allow(''),
|
||||
|
||||
// Google
|
||||
GOOGLE_API_KEY: Joi.string().allow(''),
|
||||
GOOGLE_CLIENT_SECRET: Joi.string().allow(''),
|
||||
PUBLIC_GOOGLE_CLIENT_ID: Joi.string().allow(''),
|
||||
|
||||
// SendGrid
|
||||
SENDGRID_API_KEY: Joi.string().allow(''),
|
||||
});
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
NestConfigModule.forRoot({
|
||||
load: [appConfig, authConfig, databaseConfig, googleConfig, mailConfig],
|
||||
load: [appConfig, authConfig, databaseConfig, googleConfig, sendgridConfig],
|
||||
validationSchema: validationSchema,
|
||||
}),
|
||||
],
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('mail', () => ({
|
||||
host: process.env.MAIL_HOST,
|
||||
port: parseInt(process.env.MAIL_PORT, 10) || 465,
|
||||
username: process.env.MAIL_USERNAME,
|
||||
password: process.env.MAIL_PASSWORD,
|
||||
from: process.env.MAIL_FROM,
|
||||
}));
|
|
@ -0,0 +1,8 @@
|
|||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('sendgrid', () => ({
|
||||
apiKey: process.env.SENDGRID_API_KEY,
|
||||
forgotPasswordTemplateId: process.env.SENDGRID_FORGOT_PASSWORD_TEMPLATE_ID,
|
||||
fromName: process.env.SENDGRID_FROM_NAME,
|
||||
fromEmail: process.env.SENDGRID_FROM_EMAIL,
|
||||
}));
|
|
@ -1,43 +1,36 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { readFileSync } from 'fs';
|
||||
import { compile } from 'handlebars';
|
||||
import { createTransport, Transporter } from 'nodemailer';
|
||||
import { join } from 'path';
|
||||
import SendGrid from '@sendgrid/mail';
|
||||
|
||||
import { User } from '@/users/entities/user.entity';
|
||||
|
||||
@Injectable()
|
||||
export class MailService {
|
||||
private readonly transporter: Transporter;
|
||||
|
||||
constructor(private configService: ConfigService) {
|
||||
this.transporter = createTransport(
|
||||
{
|
||||
host: this.configService.get<string>('mail.host'),
|
||||
port: this.configService.get<number>('mail.port'),
|
||||
auth: {
|
||||
user: this.configService.get<string>('mail.username'),
|
||||
pass: this.configService.get<string>('mail.password'),
|
||||
},
|
||||
},
|
||||
{
|
||||
from: this.configService.get<string>('mail.from'),
|
||||
}
|
||||
);
|
||||
SendGrid.setApiKey(this.configService.get<string>('sendgrid.apiKey'));
|
||||
}
|
||||
|
||||
async sendForgotPasswordEmail(user: User, resetToken: string) {
|
||||
async sendEmail(mail: SendGrid.MailDataRequired) {
|
||||
return SendGrid.send(mail);
|
||||
}
|
||||
|
||||
async sendForgotPasswordEmail(user: User, resetToken: string): Promise<void> {
|
||||
const appUrl = this.configService.get<string>('app.url');
|
||||
const url = `${appUrl}?modal=auth.reset&resetToken=${resetToken}`;
|
||||
const templateSource = readFileSync(join(__dirname, 'assets/templates/forgot-password.hbs'), 'utf-8');
|
||||
const template = compile(templateSource);
|
||||
const html = template({ name: user.name, url });
|
||||
|
||||
await this.transporter.sendMail({
|
||||
const mailData: SendGrid.MailDataRequired = {
|
||||
from: {
|
||||
name: this.configService.get<string>('sendgrid.fromName'),
|
||||
email: this.configService.get<string>('sendgrid.fromEmail'),
|
||||
},
|
||||
to: user.email,
|
||||
subject: 'Reset your Reactive Resume password',
|
||||
html,
|
||||
});
|
||||
hideWarnings: true,
|
||||
dynamicTemplateData: { url },
|
||||
templateId: this.configService.get<string>('sendgrid.forgotPasswordTemplateId'),
|
||||
};
|
||||
|
||||
await SendGrid.send(mailData);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue