12

I want to send PDF file in attachment using sendRawEmail(Node: aws-sdk) function, I have tried lots of ways, email sends successfully but PDF goes plain. Please correct my code and help to solve it.

Code is here:

try {
    data = fs.readFileSync('files/demo-invoice-new.pdf', 'utf8');

    console.log(data.toString());

    var ses_mail = "From: 'AWS SES Attchament Configuration' <" + SOURCE_EMAIL + ">\n";
    ses_mail = ses_mail + "To: " + toEmail + "\n";
    ses_mail = ses_mail + "Subject: AWS SES Attachment Example\n";
    ses_mail = ses_mail + "MIME-Version: 1.0\n";
    ses_mail = ses_mail + "Content-Type: multipart/mixed; boundary=\"NextPart\"\n\n";
    ses_mail = ses_mail + "--NextPart\n";
    ses_mail = ses_mail + "Content-Type: text/html; charset=us-ascii\n\n";
    ses_mail = ses_mail + "This is the body of the email.\n\n";
    ses_mail = ses_mail + "--NextPart\n";
    ses_mail = ses_mail + "Content-Type: application/octet;\n";
    ses_mail = ses_mail + "Content-Disposition: attachment; filename=\"demo-invoice-new.pdf\"\n\n";
    ses_mail = ses_mail + data.toString('utf8') + "\n\n";
    ses_mail = ses_mail + "--NextPart--";

    var params = {
        RawMessage: { Data: new Buffer(ses_mail) },
        Destinations: [toEmail],
        Source: "'AWS SES Attchament Configuration' <" + SOURCE_EMAIL + ">'"
    };

    console.log(params);

    var sendPromise = new AWS.SES(AWS_SES_CONFIG).sendRawEmail(params).promise();

    return sendPromise.then(
        data => {
            console.log(data);
            return data;
        }).catch(
        err => {
            console.error(err.message);
            throw err;
        });
} catch (e) {
    console.log('Error:', e.stack);
}
John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
Ansari Maksud
  • 316
  • 2
  • 5
  • 20

2 Answers2

31

SES raw messages must be base64-encoded. So, you'll need to get the file content as buffer and encode it as base64 string attachment. Also, you don't need to create a new buffer for raw message data since it already accepts a string data type.

OPTIONAL: You can also omit the Destinations parameter since you're already providing the To field in the raw message data. (You can also provide the Cc and Bcc fields as well)

You could try this for example:

data = fs.readFileSync("files/demo-invoice-new.pdf");

var ses_mail = "From: 'AWS SES Attchament Configuration' <" + SOURCE_EMAIL + ">\n";
ses_mail += "To: " + toEmail + "\n";
ses_mail += "Subject: AWS SES Attachment Example\n";
ses_mail += "MIME-Version: 1.0\n";
ses_mail += "Content-Type: multipart/mixed; boundary=\"NextPart\"\n\n";
ses_mail += "--NextPart\n";
ses_mail += "Content-Type: text/html\n\n";
ses_mail += "This is the body of the email.\n\n";
ses_mail += "--NextPart\n";
ses_mail += "Content-Type: application/octet-stream; name=\"demo-invoice-new.pdf\"\n";
ses_mail += "Content-Transfer-Encoding: base64\n";
ses_mail += "Content-Disposition: attachment\n\n";
ses_mail += data.toString("base64").replace(/([^\0]{76})/g, "$1\n") + "\n\n";
ses_mail += "--NextPart--";

var params = {
    RawMessage: {Data: ses_mail},
    Source: "'AWS SES Attchament Configuration' <" + SOURCE_EMAIL + ">'"
};

NOTE: The /([^\0]{76})/ regular expression replacement breaks your long lines to make sure that mail servers do not complain about message lines being too long when there is an encoded attachment, which might result in a transient bounce. (See RFC 5321)

Community
  • 1
  • 1
Khalid T.
  • 10,039
  • 5
  • 45
  • 53
  • If omitting the Destinations parameter to AWS API request, it would respond with a 400 Bad request error. I would say that this parameter can be empty, since the To, Cc and Bcc email addresses are provided. – Yajairo87 Aug 06 '19 at 17:48
8

Hi there for anybody who stumbles upon this problem I managed to solve it using nodemailer and SESV2, I had base64 encoded data so your script might be a little different from mine but the snippet below should give you an idea... Here's my solution hope it helps someone:

const MailComposer = require("nodemailer/lib/mail-composer");
const AWS = require("aws-sdk");

const generateRawMailData = (message) => {
    let mailOptions = {
        from: message.fromEmail,
        to: message.to,
        subject: message.subject,
        text: message.bodyTxt,
        html: message.bodyHtml,
        attachments: message.attachments.map(a => ({ filename: a.name, content: a.data, encoding: 'base64' }))
    };
    return new MailComposer(mailOptions).compile().build();
};

const exampleSendEmail = async () => {
    var message = {
        fromEmail: "sender@server.com",
        to: "receiver@sender.com",
        subject: "Message title",
        bodyTxt: "Plaintext version of the message",
        bodyHtml: "<p>HTML version of the message</p>",
        attachments: [{
            name: 'hello.txt',
            data: 'aGVsbG8gd29ybGQ='
        }]
    };

    let ses = new AWS.SESV2(),
    params = {
      Content: { Raw: { Data: await generateRawMailData(message) } },
      Destination: {
        ToAddresses: message.to,
        BccAddresses: message.bcc,
      },
      FromEmailAddress: message.fromEmail,
      ReplyToAddresses: message.replyTo,
    };

  return ses.sendEmail(params).promise();
}
Silvio Biasiol
  • 856
  • 8
  • 14
  • MailComposer is now deprecated. https://github.com/nodemailer/mailcomposer. Replacement - https://github.com/nodemailer/nodemailer – Akshay Jan 13 '23 at 08:02