Generate and mail qrcode without saving to local storage

Dear

Is it possible to generate a qr code(png) and mail it without saving the png to disk?

Can anybody help please. I can’t find a answer anywhere. Or I’m thinking wrong about it ?

I will let you figure out libs to do this, but your steps are:

  • generate qr code with lib to binary
  • base64 the binary
  • create html mail
  • insert img tag using the base64 string as data
  • victory

Good luck!

1 Like

Ty

You do this without an attachment?

      |> attachment(
        Swoosh.Attachment.new(
          {:data, invitation_qr_code_binary},
          filename: "qrcode.png",
          content_type: "image/png",
          type: :inline)
      )

Tried with and without attachment. I guess attachment is needed for html too?
But I see a strange preview in Swoosh’s mailbox.

preview:

  defp deliverwithattachment(recipient, subject, txtbody, htmlbody, qr_code_binary) do
    email =
      new()
      |> to(recipient)
      |> from({"something", "something@example.co"})
      |> subject(subject)
      |> text_body(txtbody)
      |> html_body(htmlbody)
      |> attachment(
        Swoosh.Attachment.new(
          {:data, qr_code_binary},
          filename: "qr.png",
          content_type: "image/png",
          type: :inline)
      )

    with {:ok, _metadata} <- Mailer.deliver(email) do
      {:ok, email}
    end
  end

def deliver_qr_email(email, url) do
    # :png64 or :jpg64
    {:ok, %Qrusty.QR{encoded_data: binary_64}} = Qrusty.qr(url, :png64, width: 200, height: 200)

    deliverwithattachment(email, "subj", """
       text only message, look in attachments...
    """,~s|
    <h2>Hallo #{email},</h2>
    <br/>
    <br/>

    <a href={"data:image/png;base64, " <> binary_64} download="qr.png">
      <img src={"data:image/png;base64, "<> binary_64}></img>
    </a>

    <img src="cid:qr.png">

    <br/>
    <br/>
    |,binary_64)
  end

Does anyone see anything wrong with this?

I don’t know if this is what you need:GitHub - bajankristof/qrcode: An Erlang library to generate QR codes.

update:
There was some bug somewhere. I could see the mails in the local mailbox but in production they wouldn’t send.

I’ve removed html_body and attachment and now :prod is sending again. I’ll try to add bit by bit again.
update2:
attachment was/is buggy for some reason

No need for attachments in the html version. I should look for a way to attach it though, but not right now

defp deliver(recipient, subject, txtbody, htmlbody) do
    email =
      new()
      |> to(recipient)
      # TODO
      |> from({"example", "example@example.com"})
      |> subject(subject)
      |> html_body(htmlbody)
      |> text_body(txtbody)

    with {:ok, _metadata} <- Mailer.deliver(email) do
      {:ok, email}
    end
  end
def deliver_type_something(email, url) do
    {:ok, %Qrusty.QR{encoded_data: binary_64}} = Qrusty.qr(url, :png64, width: 200, height: 200, ec: :m)

    deliver(
      email,
      "some subject",
      """

      ==============================

      Hallo #{email},

      #{url}

      ==============================
      """,~s|
        <h2>Hallo #{email},</h2>

        <img src="data:image/png;base64,#{binary_64}">
        
        #{url}
      |)
end
1 Like

Exactly what I meant, good work!

yes, but it isn’t good enough. People with @gmail can’t see it in the gmail app.

Is there anyone that could share some code to send a generated qr code using attachment?
Does it have to be saved to disk?

What’s wrong with this version that you posted before? As long as you have the binary of the QR code, you don’t need to save it locally as a file in order to attach it.

I can send a dev mail but it’s has errors.

I can see the attachment in the mail.
localhost:4000/dev/mailbox
screenshot_2022-10-14-141721.930
But the attachment has errors:

The image "http://localhost:4000/dev/mailbox/7374xxxxxxxxxxxxxxxxxxxxxxxx/attachments/0" cannot be displayed because it contains errors.

When I deployed it to fly, it now won’t send the mail anymore.

defp deliver(recipient, subject, txtbody, htmlbody, qrcode) do
    email =
      new()
      |> to(recipient)
      # TODO
      |> from({"example", "example@example.com"})
      |> subject(subject)
      |> html_body(htmlbody)
      |> text_body(txtbody)
      |> attachment(
        Swoosh.Attachment.new(
          {:data, qrcode},
          filename: "qrcode.png",
          content_type: "image/png",
          type: :inline
        )
      )
    with {:ok, _metadata} <- Mailer.deliver(email) do
      {:ok, email}
    end
  end

def deliver_type_something(email, url) do
    {:ok, %Qrusty.QR{encoded_data: binary_64}} = Qrusty.qr(url, :png64, width: 200, height: 200, ec: :m)

    deliver(
      email,
      "some subject",
      """

      ==============================

      Hallo #{email},

      #{url}

      ==============================
      """,~s|
        <h2>Hallo #{email},</h2>

        <img src="data:image/png;base64,#{binary_64}">
        
        <img src="cid:qrcode.png">

        #{url}
      |,
      binary_64
    )
end


Are you sure that the QR code binary is correct? If you do save it into a file with png extension, does it open as an image?

Think the QR code binary is correct because it does generate inline?

When I IO.puts:
url:
D6A0DDF60E7A676DF384CE166BF1345A10026B3C87C90F12C751F9C68BFE0AB3

binary_64:

iVBORw0KGgoAAAANSUhEUgAAAM0AAADNCAAAAAA+16u1AAAECklEQVR4nO2bUYocWQwE18ve/8rrIX4CZKmmxv0jEgXMQ1KqChKhR3dj//r/nyD+/frL4dzs5dzs5dzs5dzs5dzs5dzs5dzs5dzs5dzs5b+vvz/49fX3DfycYB+pKAAqNSKxZgSkz9gsWbM5N3vJctPeAtBtGZQNLX2dSs1IqAmqNaMCfR1Zszk3e8lyM98CUPZt3EsozeJjRPYZjZQWXjCSNZtzs5csN9/cAs+4kuyqKVDjAFRTsGb0CVmzOTd7yXLz0S3A1rK/HFBqpEBErUAN9WOyZnNu9pLl5ptbgA0dQXV/SUWhgGAzKViTrjaSNZtzs5csN/Mt4HKO0MKaEnWojhEQlRrpj8iazbnZS5ab9hZwEZ+h73lXVYl4AohKTbraC7Jmc272kuWm/X8EZTlJR0qfqSgYAWlHaSElEmqFrNmcm71kuZk/C7h0zymQIgCpIFgzKtD3zHNL1mzOzV6y3LS3QMGtZQdJjUZs4SAVa0RAVGqC8EzWbM7NXrLczLeAS8dKkpZIqHUg2GxUBFMO0y4C0kLWbM7NXrLctL8LgPs2wrP2dakgUOuiggKRWCMqZM3m3Owly017C7BlYgsCqZGUWkmBWoEWBKKRFy1Zszk3e8ly094CBdav0D1GXxGsERVGAVSJpKtB1mzOzV6y3My/C7hqHKZgSiSmqBzWwBoHWDMqUEMdyZrNudlLlpv2swD7VrCvqApQ1ILN9pXamAI1KAJkzebc7CXLTftZgAVj34iAFKzBKAA1WwQBUE3BWomAtCNrNudmL1lu2s8C4NIJzQhE0KXQ1QChq0ERRnxCsmZzbvaS5ab9LABsmStJCkaob1OjIpCKAqBaIx3Jms252UuWm/kWGPcNoexlSeVtauSrpKimhazZnJu9ZLlpvxGMW/Zx80j3Fl6AUKKRrNmcm71kuZk/C7Bvbh4Rx4h9HaPAYz+CV3WPZc3m3Owly818C0i3dNaMwAiK+oLSbNpFhazZnJu9ZLl5/Y2APgXSwqgqgGoRfoRvkazZnJu9ZLlpb4G3sMS8wEisERWKYEok1KSohazZnJu9ZLlpvxGUzesYt5FnUTlIxRoHaceojgJkzebc7CXLTXsLwLhqLKKQ0kwERNSAiBpHSYGaPKc8VmqQNZtzs5csN/MtAOybdJsHXZ81IwWjQlcDBB4byZrNudlLlptvboEXsJdsaAEBVIkUBEFsKcIzWbM5N3vJcvPRLcCusqZEQMpB7TkSUgUjIAWjjqzZnJu9ZLn55hZwEf8SX0DkEhOVGqkgvKhJ1mzOzV6y3My3APv2TNfChiJwCAKHghGU1GaiF2TN5tzsJcvNR/9eYB1Zszk3ezk3ezk3ezk3ezk3ezk3ezk3ezk3ezk3e/kNFjXyue/HKZIAAAAASUVORK5CYII=

mailbox:

It’s really easy. But I didn’t spot it.
png64 is wrong for an attachment, it does work for inline

    # inline: this doesn't work for google/gmail
    # :png64 or :jpg64
    {:ok, %Qrusty.QR{encoded_data: binary_64}} =
      Qrusty.qr(url, :png64, width: 200, height: 200, ec: :m)

    # attachment
    {:ok, %Qrusty.QR{encoded_data: binary}} =
      Qrusty.qr(url, :png, width: 200, height: 200, ec: :m)
1 Like

Yes, but in the attachment you should not use the Base64 encoded binary, but the raw one instead.

The Base64 encoded version is ok to use inside a data URL like <img src="data:image/png;base64,#{binary_64}">.

But when you call the attachment function you have to pass a PNG binary, not Base64 encoded. In other words, a binary that you could write in a file with png extension, and it would open as an image.

If you pass the binary_64 in your code to Base.decode64! you get the raw PNG that you can use in the attachment.

# qrcode here should be a raw png binary
|> attachment(
  Swoosh.Attachment.new(
    {:data, qrcode},
    filename: "qrcode.png",
    content_type: "image/png",
    type: :inline
  )
)

EDIT: I see you replied right when I posted this message with the same solution :slight_smile:

1 Like

This doesn’t solve it completely.
I see the mail as expected in the dev mailbox.
But it doesn’t work in production. Postmark doesn’t see it, so It’ll never be received.
I think it’s related to the cid

This works and shows the url 3 times:

  1. qr code attachment with cid
  2. qr code inline
  3. string
defp deliver(recipient, subject, txtbody, htmlbody, qrcode_binary) do
    email =
      new()
      |> to(recipient)
      # TODO
      |> from({"example", "example@example.com"})
      |> subject(subject)
      |> html_body(htmlbody)
      |> text_body(txtbody)
      |> attachment(
        Swoosh.Attachment.new(
          {:data, qrcode_binary},
          filename: "qrcode.png",
          content_type: "image/png",
          type: :inline,
          cid: "qrcode.png"
        )
      )
    with {:ok, _metadata} <- Mailer.deliver(email) do
      {:ok, email}
    end
  end

def deliver_type_something(email, url) do
    # 1 attachment with cid
    {:ok, %Qrusty.QR{encoded_data: binary}} = Qrusty.qr(url, :png, width: 200, height: 200, ec: :m)
    # 2 inline
    {:ok, %Qrusty.QR{encoded_data: binary_64}} = Qrusty.qr(url, :png64, width: 200, height: 200, ec: :m)

    deliver(
      email,
      "some subject",
      """

      ==============================

      Hallo #{email},

      #{url}

      ==============================
      """,~s|
        <h2>Hallo #{email},</h2>

        1 attachment
        <img src="cid:qrcode.png">

        2 inline
        <img src="data:image/png;base64,#{binary_64}">

        3 string
        #{url}
      |,
      binary
    )
end

I’ll test this tomorrow in production. If the attachment qr is always visible, I’ll remove the inline one.