Browse Source

feat(server): Improve email previews when using "file" transport

Michael Bromley 7 years ago
parent
commit
66095db71c

+ 1 - 0
server/dev-config.ts

@@ -39,6 +39,7 @@ export const devConfig: VendureConfig = {
         generator: new HandlebarsMjmlGenerator(path.join(__dirname, 'src', 'email', 'templates', 'partials')),
         transport: {
             type: 'file',
+            raw: false,
             outputPath: path.join(__dirname, 'test-emails'),
         },
     },

+ 12 - 0
server/src/config/email/email-transport-options.ts

@@ -28,6 +28,9 @@ export interface SMTPTransportOptions {
     authMethod?: string;
 }
 
+/**
+ * Uses the local Sendmail program to send the email.
+ */
 export interface SendmailTransportOptions {
     type: 'sendmail';
     /** path to the sendmail command (defaults to ‘sendmail’) */
@@ -36,11 +39,20 @@ export interface SendmailTransportOptions {
     newline?: string;
 }
 
+/**
+ * Outputs the email as an HTML file for development purposes.
+ */
 export interface FileTransportOptions {
     type: 'file';
+    /** The directory in which the emails will be saved */
     outputPath: string;
+    /** When set to true, a raw text file will be output rather than an HTML file */
+    raw: boolean;
 }
 
+/**
+ * Does nothing with the generated email. Mainly intended for use in testing.
+ */
 export interface NoopTransportOptions {
     type: 'none';
 }

+ 58 - 8
server/src/email/email-sender.ts

@@ -8,7 +8,7 @@ import { normalizeString } from 'shared/normalize-string';
 import { assertNever } from 'shared/shared-utils';
 import { Stream } from 'stream';
 
-import { EmailTransportOptions } from '../config/email/email-transport-options';
+import { EmailTransportOptions, FileTransportOptions } from '../config/email/email-transport-options';
 
 import { GeneratedEmailContext } from './email-context';
 
@@ -30,16 +30,16 @@ export class EmailSender {
                 return;
                 break;
             case 'file':
-                transporter = createTransport({
-                    streamTransport: true,
-                });
-                const result = await this.sendMail(email, transporter);
                 const fileName = normalizeString(
-                    `${new Date().toISOString()} ${result.envelope.to[0]} ${email.subject}`,
+                    `${new Date().toISOString()} ${email.recipient} ${email.subject}`,
                     '_',
                 );
                 const filePath = path.join(options.outputPath, fileName);
-                await this.writeToFile(filePath, result);
+                if (options.raw) {
+                    await this.sendFileRaw(email, filePath);
+                } else {
+                    await this.sendFileHtml(email, filePath);
+                }
                 break;
             case 'sendmail':
                 transporter = createTransport({
@@ -70,7 +70,57 @@ export class EmailSender {
         });
     }
 
-    private async writeToFile(filePath: string, info: StreamTransportInfo): Promise<string> {
+    private async sendFileHtml(email: GeneratedEmailContext, pathWithoutExt: string) {
+        const content = `<html>
+            <head>
+                <title>${email.subject}</title>
+                <style>
+                    body {
+                        display: flex;
+                        flex-direction: column;
+                        font-family: Helvetica, Arial, sans-serif;
+                    }
+                    iframe {
+                        flex: 1;
+                        border: 1px solid #aaa;
+                    }
+                </style>
+            </head>
+            <body>
+            <div class="metadata">
+                <table>
+                    <tr>
+                        <td>Recipient:</td>
+                        <td>${email.recipient}</td>
+                    </tr>
+                    <tr>
+                        <td>Subject:</td>
+                        <td>${email.subject}</td>
+                    </tr>
+                    <tr>
+                        <td>Date:</td>
+                        <td>${new Date().toLocaleString()}</td>
+                    </tr>
+                </table>
+            </div>
+            <iframe srcdoc="${email.body.replace(/"/g, '&quot;')}"></iframe>
+            </body>
+            </html>
+        `;
+
+        await fs.writeFile(pathWithoutExt + '.html', content);
+    }
+
+    private async sendFileRaw(email: GeneratedEmailContext, pathWithoutExt: string) {
+        const transporter = createTransport({
+            streamTransport: true,
+            buffer: true,
+        });
+        const result = await this.sendMail(email, transporter);
+        await this.writeStreamToFile(pathWithoutExt + '.txt', result);
+    }
+
+    private async writeStreamToFile(filePath: string, info: StreamTransportInfo): Promise<string> {
         const writeStream = fs.createWriteStream(filePath);
         return new Promise<string>((resolve, reject) => {
             writeStream.on('open', () => {