EC-Nordbund / denomailer

A SMTP-Client implementation for deno (to send mails!)
https://deno.land/x/denomailer
MIT License
50 stars 16 forks source link

Issues with sending binary data attachment #25

Closed rdelpeso closed 2 years ago

rdelpeso commented 2 years ago

Hi, I am likely doing something wrong. I love the lib but I can't figure out how to send a PNG attachment with it. This is what am doing, any suggestions?

const file = await Deno.readFile("./test.png");
await client.send({
  attachments: [
    {
      contentType: "image/png",
      filename: "test.png",
      encoding: "binary",
      content: file,
    },
  ],
  from: "address@gmail.com",
  to: "address@gmail.com",
  subject: "Img Test",
  content: "",
  html:
    "<b>Testing with html and image.</b>",
});

When I compare the original PNG and the Sent one. This line is extra on the top of the binary blob:

original.png

‰PNG

received.png

Content-Transfer-Encoding: binary
‰PNG

Bonus: Could we add "Content-ID" to the library to support embedding the image on the html? 😄

mathe42 commented 2 years ago

Not sure why this happens. Currently not home so will take a week at least to look into it.

rdelpeso commented 2 years ago

Appreciate it. I will take a stab at it this weekend and submit a pull request if I figure it out. Was just worried I was being blind and missing something 👍

mathe42 commented 2 years ago

For the Feature request:

I'm currently in a phase where I will not implement new features as I don't have (currently!) the time for that. But I would except a PR.

mathe42 commented 2 years ago

https://github.com/EC-Nordbund/denomailer/blob/7da737e17c989695de9ec8788de66f8ed5889035/client/basic/client.ts#L263

I think this Line might be the problem could you try it when there is no \r\n?

rdelpeso commented 2 years ago

Sadly no matter what I did, Gmail refuses to receive the binary attachment.

I've forked the repo, and made some changes to allow for base64 attachments and added some defaults for X-Attachment-Id and Content-ID. Without those, Gmail also refused to work for base64.

For some reason I also had to quote the file name of the attachment on the Content-Type and Content-Disposition. Gmail is wonky it seems ¯_(ツ)_/¯

Not sure if the changes are up to your taste. Take a look at them when you can, and let me know if you want me to create a PR to make it official.

https://github.com/rdelpeso/denomailer/commit/a39bada309f471ff287dc8ea2e5b532878334499

Now this example works perfectly:

const file = await Deno.readFile("./test.png");

import { encode } from "https://deno.land/std/encoding/base64.ts";
const b64 = encode(file);

await client.send({
  attachments: [
    {
      contentType: "image/png",
      filename: "test_64.png",
      encoding: "base64",
      content: b64,
    },
  ],
  from: "address@gmail.com",
  to: "address@gmail.com",
  subject: "Img Test",
  content: "",
  html:
    // cid:attachment_id_0 -> just means the 0th (or first) attachment, this supports embedding now 😄 
    "<b>Testing with html and image.</b><br/><img src="cid:attachment_id_0"/>",
});
rdelpeso commented 2 years ago

So apparently the fix only worked for Gmail, hotmail is still busted and regardless of using base64 or binary, the attachments are corrupted on the receiving side. haiz...

mathe42 commented 2 years ago

Will look at it in friday currently not home...

mathe42 commented 2 years ago

@rdelpeso I fixed one problem. Can you try when importing from https://raw.githubusercontent.com/EC-Nordbund/denomailer/fix/binary-attachments/mod.ts ?

The tests currently only show a extra "\r\n" at the end of the file but that might be a problem with fake-smtp-server (my testing tool).

I tested 1 SMTP server with a single image and had no problem.

rdelpeso commented 2 years ago

No luck, the file keeps getting corrupted

image image

Not sure what is going on. Maybe the GMAIL SMTP server behaves differently than the SMTP server you are using?

I am connecting with:

const client = new SMTPClient({
  debug: {
    log: true,
  },
  connection: {
    hostname: "smtp.gmail.com",
    port: 465,
    tls: true,
    auth: {
      username: creds.user,
      password: creds.pass,
    },
  },
});

Using binary has never worked for me with this connection. I do not have any other SMTP server to test with sadly. It may just be that GMAIL SMTP does not support binary attachments at all.

rdelpeso commented 2 years ago

Also notice this:

Original File: image

After email sent file: image

So, all \r are being transformed to \r\n and all \n are being transformed to \r\n

Which corrupts the image entirely. Either writer is doing that, or GMAIL SMTP is doing it.

mathe42 commented 2 years ago

Thanks for testing!

mathe42 commented 2 years ago

I could reproduce it with the same image and gmail i get problems with gmx (a german provider) I have no problems.

mathe42 commented 2 years ago

Got it...

content-encoding isn't valid... You have to use BINARYMIME. That means that I will rewrite it so that (for now) attachments will be base64 encoded and will later add support for BINARYMIME as I have to read and learn some stuff for that.

Refrences

  1. https://stackoverflow.com/a/28531705
  2. https://datatracker.ietf.org/doc/html/rfc3030
mathe42 commented 2 years ago

Released 1.2 with a fix