typescriptnestjsnodemailerexceljs

Send email with Excel attachment using @nestjs/mailer


I'm trying to send email with excel attachment through @nestjs/mailer:

await this.mailService.send({ //service with @nestjs/mailer
      to: messageTo,
      subject: messageTitle,
      template: 'application-approved',
      context: {
        content: messageBody,
      },
      attachments: attachments.map(({ name, arrayBuffer }) => ({ // array with filenames and arrayBuffers
        filename: name, // filename like `name.xlsx`
        contents: arrayBuffer, // arrayBuffer contains filled excel file
        contentType: // tried to remove this property - no effect
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      })),
    });

When a message arrives, all attachments are marked as broken. I tried to send both ArrayBuffer and Buffer - It had no effect.

In other hand HTTP route that creates the file and attach it to response succeeds.

Any ideas to solve this problem?


Solution

  • I never used @nestjs/mailer, but since it uses nodemailer under the hood, I would try this:

    await this.mailService.send({
      to: messageTo,
      subject: messageTitle,
      template: 'application-approved',
      context: {
        content: messageBody,
      },
      attachments: attachments.map(({ name, arrayBuffer }) => ({
        filename: name,
        contents: Buffer.from(arrayBuffer).toString('base64'),
        contentTransferEncoding: 'base64',
        contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      })),
    });
    

    If that doesn't work, maybe you should check if the file content is correct in the first place. You can save the file on the disk and open it, if that doesn't work then it's a data problem, not a transfer problem.

    Also, check the type definitions for nodemailer attachments, to see what other options you have:

    interface AttachmentLike {
      /** String, Buffer or a Stream contents for the attachmentent */
      content?: string | Buffer | Readable | undefined;
      /** path to a file or an URL (data uris are allowed as well) if you want to stream the file instead of including it (better for larger attachments) */
      path?: string | Url | undefined;
    }
    
    interface Attachment extends AttachmentLike {
      /** filename to be reported as the name of the attached file, use of unicode is allowed. If you do not want to use a filename, set this value as false, otherwise a filename is generated automatically */
      filename?: string | false | undefined;
      /** optional content id for using inline images in HTML message source. Using cid sets the default contentDisposition to 'inline' and moves the attachment into a multipart/related mime node, so use it only if you actually want to use this attachment as an embedded image */
      cid?: string | undefined;
      /** If set and content is string, then encodes the content to a Buffer using the specified encoding. Example values: base64, hex, binary etc. Useful if you want to use binary attachments in a JSON formatted e-mail object */
      encoding?: string | undefined;
      /** optional content type for the attachment, if not set will be derived from the filename property */
      contentType?: string | undefined;
      /** optional transfer encoding for the attachment, if not set it will be derived from the contentType property. Example values: quoted-printable, base64. If it is unset then base64 encoding is used for the attachment. If it is set to false then previous default applies (base64 for most, 7bit for text). */
      contentTransferEncoding?: '7bit' | 'base64' | 'quoted-printable' | false | undefined;
      /** optional content disposition type for the attachment, defaults to ‘attachment’ */
      contentDisposition?: 'attachment' | 'inline' | undefined;
      /** is an object of additional headers */
      headers?: Headers | undefined;
      /** an optional value that overrides entire node content in the mime message. If used then all other options set for this node are ignored. */
      raw?: string | Buffer | Readable | AttachmentLike | undefined;
    }