email-processor.ts 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import { InternalServerError, Logger } from '@vendure/core';
  2. import fs from 'fs-extra';
  3. import { isDevModeOptions } from './common';
  4. import { loggerCtx } from './constants';
  5. import { EmailSender } from './email-sender';
  6. import { HandlebarsMjmlGenerator } from './handlebars-mjml-generator';
  7. import { TemplateLoader } from './template-loader';
  8. import { EmailPluginOptions, EmailTransportOptions, IntermediateEmailDetails } from './types';
  9. /**
  10. * This class combines the template loading, generation, and email sending - the actual "work" of
  11. * the EmailPlugin. It is arranged this way primarily to accomodate easier testing, so that the
  12. * tests can be run without needing all the JobQueue stuff which would require a full e2e test.
  13. */
  14. export class EmailProcessor {
  15. protected templateLoader: TemplateLoader;
  16. protected emailSender: EmailSender;
  17. protected generator: HandlebarsMjmlGenerator;
  18. protected transport: EmailTransportOptions;
  19. constructor(protected options: EmailPluginOptions) {}
  20. async init() {
  21. this.templateLoader = new TemplateLoader(this.options.templatePath);
  22. this.emailSender = new EmailSender();
  23. this.generator = new HandlebarsMjmlGenerator();
  24. if (this.generator.onInit) {
  25. await this.generator.onInit.call(this.generator, this.options);
  26. }
  27. if (isDevModeOptions(this.options)) {
  28. this.transport = {
  29. type: 'file',
  30. raw: false,
  31. outputPath: this.options.outputPath,
  32. };
  33. } else {
  34. if (!this.options.transport) {
  35. throw new InternalServerError(
  36. `When devMode is not set to true, the 'transport' property must be set.`,
  37. );
  38. }
  39. this.transport = this.options.transport;
  40. }
  41. if (this.transport.type === 'file') {
  42. // ensure the configured directory exists before
  43. // we attempt to write files to it
  44. const emailPath = this.transport.outputPath;
  45. await fs.ensureDir(emailPath);
  46. }
  47. }
  48. async process(data: IntermediateEmailDetails) {
  49. try {
  50. const bodySource = await this.templateLoader.loadTemplate(data.type, data.templateFile);
  51. const generated = await this.generator.generate(
  52. data.from,
  53. data.subject,
  54. bodySource,
  55. data.templateVars,
  56. );
  57. const emailDetails = { ...generated, recipient: data.recipient };
  58. await this.emailSender.send(emailDetails, this.transport);
  59. return true;
  60. } catch (err: unknown) {
  61. if (err instanceof Error) {
  62. Logger.error(err.message, loggerCtx, err.stack);
  63. } else {
  64. Logger.error(String(err), loggerCtx);
  65. }
  66. return false;
  67. }
  68. }
  69. }