Skip to content

Commit

Permalink
Merge pull request #21 from kuzzleio/feat/sendgrid-support-attachments
Browse files Browse the repository at this point in the history
feat: sendgrid support attachments
  • Loading branch information
etrousset authored Aug 21, 2024
2 parents 70cf40a + f9bc939 commit 92bb591
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/actions/functional-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ runs:
shell: bash
run: |
npm run docker npm ci
docker-compose up -d
docker compose up -d
bash tests/wait-kuzzle.sh
npm run test
9 changes: 9 additions & 0 deletions doc/1/controllers/sendgrid/sendEmail/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ Method: POST
"subject": "<email subject>",
"html": "<email body>",
"from": "<sender email>", // optional
"attachments": [ // optional
{
"content": "<base64 encoded attachment content>",
"contentType": "<attachment content type>",
"filename": "<attachment file name>",
"contentDisposition": "attachment" | "inline",
"cid": "<content ID if inline attachment>" // optional
}
]
}
}
```
Expand Down
9 changes: 9 additions & 0 deletions doc/1/controllers/sendgrid/sendTemplatedEmail/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ Method: POST
},
"templateId": "<template ID>",
"from": "<sender email>", // optional
"attachments": [ // optional
{
"content": "<base64 encoded attachment content>",
"contentType": "<attachment content type>",
"filename": "<attachment file name>",
"contentDisposition": "attachment" | "inline",
"cid": "<content ID if inline attachment>" // optional
}
]
}
}
```
Expand Down
3 changes: 3 additions & 0 deletions lib/HermesMessengerPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,12 @@ export class HermesMessengerPlugin extends Plugin {
properties: {
content: { type: "keyword" },
contentType: { type: "keyword" },
type: { type: "keyword" },
filename: { type: "keyword" },
contentDisposition: { type: "keyword" },
disposition: { type: "keyword" },
cid: { type: "keyword" },
content_id: { type: "keyword" },
},
},

Expand Down
31 changes: 26 additions & 5 deletions lib/controllers/SendgridController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ import {
PluginContext,
ControllerDefinition,
} from "kuzzle";

import { SendgridClient } from "../messenger-clients";
import { Attachment, SendgridAttachment } from "lib/types";

export class SendgridController {
private context: PluginContext;
private config: JSONObject;

private sendgridClient: SendgridClient;

definition: ControllerDefinition;

get sdk(): EmbeddedSDK {
Expand Down Expand Up @@ -64,7 +62,20 @@ export class SendgridController {

const from = fromEmail.length === 0 ? null : fromEmail;

await this.sendgridClient.sendEmail(account, to, subject, html, { from });
const attachments = request.getBodyArray("attachments", []).map(
(attachment: Attachment): SendgridAttachment => ({
content: attachment.content,
filename: attachment.filename,
type: attachment.contentType,
disposition: attachment.contentDisposition,
content_id: attachment.cid,
})
);

await this.sendgridClient.sendEmail(account, to, subject, html, {
from,
attachments,
});
}

async sendTemplatedEmail(request: KuzzleRequest) {
Expand All @@ -76,12 +87,22 @@ export class SendgridController {

const from = fromEmail.length === 0 ? null : fromEmail;

const attachments = request.getBodyArray("attachments", []).map(
(attachment: Attachment): SendgridAttachment => ({
content: attachment.content,
filename: attachment.filename,
type: attachment.contentType,
disposition: attachment.contentDisposition,
content_id: attachment.cid,
})
);

await this.sendgridClient.sendTemplatedEmail(
account,
to,
templateId,
templateData,
{ from }
{ from, attachments }
);
}

Expand Down
32 changes: 24 additions & 8 deletions lib/messenger-clients/SendgridClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MailService } from "@sendgrid/mail";
import { ExternalServiceError, JSONObject } from "kuzzle";

import { BaseAccount, MessengerClient } from "./MessengerClient";
import { SendgridAttachment } from "lib/types";

export interface SendgridAccount extends BaseAccount<MailService> {
options: {
Expand All @@ -25,24 +26,34 @@ export class SendgridClient extends MessengerClient<SendgridAccount> {
* @param subject Email subject
* @param html Email content
* @param options.from Sender email
* @param options.attachments Attachments to be included in the email
*/
async sendEmail(
accountName: string,
to: string[],
subject: string,
html: string,
{ from }: { from?: string } = {}
{
from,
attachments,
}: { from?: string; attachments?: SendgridAttachment[] } = {}
) {
const account = this.getAccount(accountName);

const fromEmail = from || account.options.defaultSender;

const email = { from: fromEmail, to, subject, html };
const email = {
from: fromEmail,
to,
subject,
html,
attachments,
};

this.context.log.debug(
`EMAIL (${accountName}): FROM ${fromEmail} TO ${to.join(
", "
)} SUBJECT ${subject}`
)} SUBJECT ${subject} ATTACHMENTS ${attachments?.length || 0}`
);

try {
Expand All @@ -59,20 +70,24 @@ export class SendgridClient extends MessengerClient<SendgridAccount> {
}

/**
* Sends a tempated email using one of the registered accounts.
* Sends a templated email using one of the registered accounts.
*
* @param accountName Account name
* @param from Sender email
* @param to Recipient email(s)
* @param templateId Template ID
* @param templateData Template placeholders values
* @param options.from Sender email
* @param options.attachments Attachments to be included in the email
*/
async sendTemplatedEmail(
accountName: string,
to: string[],
templateId: string,
templateData: JSONObject,
{ from }: { from?: string } = {}
{
from,
attachments,
}: { from?: string; attachments?: SendgridAttachment[] } = {}
) {
const account = this.getAccount(accountName);

Expand All @@ -83,12 +98,13 @@ export class SendgridClient extends MessengerClient<SendgridAccount> {
to,
templateId,
dynamic_template_data: templateData,
attachments,
};

this.context.log.debug(
`EMAIL (${accountName}): FROM ${fromEmail} TO ${to.join(
", "
)} TEMPLATE ${templateId}`
)} TEMPLATE ${templateId} ATTACHMENTS ${attachments?.length || 0}`
);

try {
Expand Down Expand Up @@ -127,7 +143,7 @@ export class SendgridClient extends MessengerClient<SendgridAccount> {
};
}

private async sendMessage(account: SendgridAccount, email: any) {
private async sendMessage(account: SendgridAccount, email) {
if (await this.mockedAccount(account.name)) {
await this.sdk.document.createOrReplace(
this.config.adminIndex,
Expand Down
8 changes: 8 additions & 0 deletions lib/types/Attachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ export interface Attachment {
contentDisposition: "attachment" | "inline";
cid?: string;
}

export interface SendgridAttachment {
content: string;
type: string;
filename: string;
disposition: "attachment" | "inline";
content_id?: string;
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"docker": "docker-compose run kuzzle_node_1 ",
"docker": "docker compose run kuzzle_node_1 ",
"dev": "NODE_ENV=development ergol tests/application/app.ts -c ergol.config.json",
"prod": "node ./dist/tests/application/app.js",
"test": "jest --runInBand",
Expand Down
9 changes: 9 additions & 0 deletions tests/scenarios/sendgrid.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ describe("Sendgrid", () => {
from: "[email protected]",
to: ["[email protected]"],
templateData: { foo: "bar" },
attachments: [
{
content: "base64filecontent",
filename: "dummyfile.pdf",
contentType: "pdf",
contentDisposition: "inline",
content_id: "dummyCid",
},
],
},
});

Expand Down
2 changes: 1 addition & 1 deletion tests/wait-kuzzle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ do
((tries=tries+1))

if [ $tries -eq $max_tries ]; then
docker-compose logs
docker compose logs
curl http://localhost:7512?pretty
echo "Cannot connect to Kuzzle after $tries tries. Aborting."
exit 1
Expand Down

0 comments on commit 92bb591

Please sign in to comment.