Skip to content

Commit

Permalink
feat: use mailjet in production
Browse files Browse the repository at this point in the history
  • Loading branch information
Leoglme committed Jan 27, 2024
1 parent d7746bf commit 19cd3c5
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 105 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/deploy-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,8 @@ jobs:
sed -i "s|MYSQL_HOST=.*|MYSQL_HOST=${{ secrets.DATABASE_HOST }}|" .env
sed -i "s|MYSQL_USER=.*|MYSQL_USER=${{ secrets.DATABASE_USERNAME }}|" .env
sed -i "s|MYSQL_PASSWORD=.*|MYSQL_PASSWORD=${{ secrets.DATABASE_PASSWORD }}|" .env
sed -i "s|SMTP_HOST=.*|SMTP_HOST=${{ secrets.SMTP_HOST }}|" .env
sed -i "s|SMTP_PORT=.*|SMTP_PORT=${{ secrets.SMTP_PORT }}|" .env
sed -i "s|SMTP_USERNAME=.*|SMTP_USERNAME=${{ secrets.SMTP_USERNAME }}|" .env
sed -i "s|SMTP_PASSWORD=.*|SMTP_PASSWORD=${{ secrets.SMTP_PASSWORD }}|" .env
sed -i "s|MAILJET_API_SECRET_KEY=.*|MAILJET_API_SECRET_KEY=${{ secrets.MAILJET_API_SECRET_KEY }}|" .env
sed -i "s|MAILJET_API_KEY=.*|MAILJET_API_KEY=${{ secrets.MAILJET_API_KEY }}|" .env
sed -i "s|GOOGLE_API_KEY=.*|GOOGLE_API_KEY=${{ secrets.GOOGLE_API_KEY }}|" .env
sed -i "s|GOOGLE_CLIENT_ID=.*|GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}|" .env
sed -i "s|GOOGLE_CLIENT_SECRET=.*|GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}|" .env
Expand Down
2 changes: 2 additions & 0 deletions api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ APP_PRIMARY_COLOR="#db0a61"
APP_EMAIL_NO_REPLY=no-reply@aparteasy.dibodev.com
APP_EMAIL_SUPPORT=support@aparteasy.dibodev.com
SESSION_DRIVER=cookie
MAILJET_API_SECRET_KEY=none
MAILJET_API_KEY=none
6 changes: 2 additions & 4 deletions api/.env.production
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ MYSQL_DATABASE=
MYSQL_HOST=
MYSQL_PASSWORD=
MYSQL_USER=
SMTP_HOST=
SMTP_PASSWORD=
SMTP_PORT=
SMTP_USERNAME=
MAILJET_API_SECRET_KEY=
MAILJET_API_KEY=
GOOGLE_API_KEY=
GOOGLE_CALLBACK_URL=
GOOGLE_CLIENT_ID=
Expand Down
146 changes: 90 additions & 56 deletions api/app/Services/MailService.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
import Mail from '@ioc:Adonis/Addons/Mail'
import type { MailMessage, MailsMessages } from '@ioc:Adonis/Addons/Mail'
import Mail, { BaseMailer } from '@ioc:Adonis/Addons/Mail'
import type { MessageContract } from '@ioc:Adonis/Addons/Mail'
import Env from '@ioc:Adonis/Core/Env'
import View from '@ioc:Adonis/Core/View'
import mjml from 'mjml'
import Mailjet from 'node-mailjet'
import type { LibraryResponse } from 'node-mailjet'
import Logger from '@ioc:Adonis/Core/Logger'
import appInfos from 'Config/app-infos'
import type { RequestData } from 'node-mailjet/declarations/request/Request'

export default class MailService {
protected static replyTo = {
type MailReplayTo = {
email: string
name: string
}

interface BaseMailPayload {
payload?: Record<string, unknown>
subject?: string
viewPath?: string
}

interface MailPayload extends BaseMailPayload {
email: string
}

interface MailManyPayload extends BaseMailPayload {
emails: string[]
}

export default class MailService extends BaseMailer {
protected static replyTo: MailReplayTo = {
email: appInfos.emails.support,
name: `${appInfos.name} Team`,
}
Expand All @@ -15,70 +39,80 @@ export default class MailService {
payload,
subject,
viewPath = 'emails/test-email',
}: {
email: string
payload?: Record<string, unknown>
subject?: string
viewPath?: string
}): Promise<void> {
const mail: MailMessage = {
viewPath,
from: appInfos.emails.noReply,
to: email,
subject: subject,
replyTo: this.replyTo,
payload,
}
}: MailPayload): Promise<void> {
const html: string = this.getHtml(viewPath, payload)

const html = this.getHtml(mail.viewPath, mail.payload)
await Mail.sendLater((message) => {
message
.from(mail.from)
.to(mail.to)
.subject(mail.subject || '')
.replyTo(mail.replyTo.email || mail.to, mail.replyTo.name)
.html(html)
})
const isProduction: boolean = Env.get('NODE_ENV') === 'production'

if (isProduction) {
// Use Mailjet in production
this.sendMailWithMailjet({ email, payload, subject, viewPath })
} else {
// Use the classic operation of Adonis Mail in development
await Mail.sendLater((message: MessageContract): void => {
message
.from(appInfos.emails.noReply)
.to(email)
.subject(subject || '')
.replyTo(this.replyTo.email, this.replyTo.name)
.html(html)
})
}
}

public static async sendMany({
emails,
payload,
subject,
viewPath = 'emails/test-email',
}: {
emails: string[]
payload?: Record<string, unknown>
subject?: string
viewPath?: string
}) {
const mails: MailsMessages = {
viewPath,
from: appInfos.emails.noReply,
to: emails,
subject: subject,
replyTo: {
email: appInfos.emails.support,
name: `${appInfos.name} Team`,
},
payload,
}: MailManyPayload): Promise<void> {
const uniqueEmails: string[] = [...new Set(emails)]

for (const email of uniqueEmails) {
await this.send({ email, payload, subject, viewPath })
}
}

const receivers: string[] = []
const html = this.getHtml(mails.viewPath, mails.payload)
mails.to.map(async (mail) => {
if (receivers.includes(mail)) return
receivers.push(mail)
public static sendMailWithMailjet({
email,
payload,
subject,
viewPath = 'emails/test-email',
}: MailPayload): void {
const html: string = this.getHtml(viewPath, payload)

await Mail.sendLater((message) => {
message
.from(mails.from)
.to(mail)
.subject(mails.subject || '')
.replyTo(mails.replyTo.email || mail, mails.replyTo.name)
.html(html)
})
const mailjet: Mailjet = new Mailjet({
apiKey: Env.get('MAILJET_API_KEY'),
apiSecret: Env.get('MAILJET_API_SECRET_KEY'),
})

const request: Promise<LibraryResponse<RequestData>> = mailjet
.post('send', { version: 'v3.1' })
.request({
Messages: [
{
From: {
Email: appInfos.emails.noReply,
Name: this.replyTo.name,
},
To: [{ Email: email }],
Subject: subject,
HTMLPart: html,
ReplyTo: {
Email: this.replyTo.email,
Name: this.replyTo.name,
},
},
],
})

request
.then((result: LibraryResponse<RequestData>): void => {
Logger.info('Mail sent successfully with Mailjet:', JSON.stringify(result.body))
})
.catch((error): void => {
Logger.error('Error sending mail with Mailjet:', JSON.stringify(error.statusCode))
})
}

protected static getHtml(viewPath: string, payload?: Record<string, unknown>): string {
Expand Down
1 change: 1 addition & 0 deletions api/app/Services/SocialAuthService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default class SocialAuthService extends BaseService {

if (!user) {
user = await this.createUser(socialUser, provider)
await super.sendPrivateSocketEvent({ user }, 'new:user')
}

if (!user?.oauthProviderName) {
Expand Down
38 changes: 0 additions & 38 deletions api/config/mail.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,9 @@
/**
* Config source: https://git.io/JvgAf
*
* Feel free to let us know via PR, if you find something broken in this contract
* file.
*/

import Env from '@ioc:Adonis/Core/Env'
import { mailConfig } from '@adonisjs/mail/build/config'

export default mailConfig({
/*
|--------------------------------------------------------------------------
| Default mailer
|--------------------------------------------------------------------------
|
| The following mailer will be used to send emails, when you don't specify
| a mailer
|
*/
mailer: 'smtp',

/*
|--------------------------------------------------------------------------
| Mailers
|--------------------------------------------------------------------------
|
| You can define or more mailers to send emails from your application. A
| single `driver` can be used to define multiple mailers with different
| config.
|
| For example: Postmark driver can be used to have different mailers for
| sending transactional and promotional emails
|
*/
mailers: {
/*
|--------------------------------------------------------------------------
| Smtp
|--------------------------------------------------------------------------
|
| Uses SMTP protocol for sending email
|
*/
smtp: {
driver: 'smtp',
pool: true,
Expand Down
65 changes: 62 additions & 3 deletions api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 19cd3c5

Please sign in to comment.