Azure / Microsoft365R

R SDK for interacting with Microsoft 365 APIs
Other
313 stars 44 forks source link

Multiple Images Not Loading in Blastula Email #107

Closed Tom271 closed 1 year ago

Tom271 commented 2 years ago

I'm trying to send an email through Outlook that is created using the blastula package. It's quite a complex email with 6 inline images. The mail renders and sends correctly when using blastula::render_email and blastula::smtp_send from a gmail account. The issue arises when using create_email. The email sends successfully, however the inline images are missing. The missing images refer to originalsrc=cid:img1.png etc. . They are all attached, all with the same file name (in this case img6.png) - in fact the final image is the only one that shows correctly in the sent email. After digging around in the code, I think it is something to do with Line 22 in make_email_attachments.R https://github.com/Azure/Microsoft365R/blob/c2762e362c647ac6e6639151040a69028a59dda3/R/make_email_attachments.R#L22 This line fixes the name for every image in the blastula email.

I've cloned the repo and adjusted this to names(object$images)[i] , which works in naming each image file differently, however now no images are inlined. It seems this change is changing the src somehow. From here I've hit a dead end, I'm not sure how to trace the issue back any further. The images are all small (passing the is_small_attachment if clause) so that's not the issue.

Any ideas on how to resolve this? I'm happy to help out with implementing the fix.

I'm using blastula v0.3.2 and Microsoft365R v2.3.4

hongooi73 commented 2 years ago

Can you give an example of a blastula email object that has this problem?

Tom271 commented 2 years ago

I'm creating the email using:

library(Microsoft365R)
mail <- blastula::render_email("test_report.Rmd")
mail
outlb <- get_business_outlook()
subject <- "Test Email"
em <- outlb$create_email(mail, subject=subject, to="an_email_account")
em$send()

where the test_report.Rmd file is

---
title : "Test"
output:
  html_fragment:
    fig_retina: 1
---
# Example text 
Test blastula mail

    ```{r}

    library(tidyverse)
    library(ggplot2)

    data(mtcars)
    mtcars %>% ggplot() + geom_line(aes(x=mpg, y=hp))

Example text after where the image should be placed


The email sends successfully, appearing as follows:
![image](https://user-images.githubusercontent.com/7256543/159896862-c024fa9a-2235-4f9a-b6de-383e49133b6b.png)
Inspecting the html shows that an `<img>` tag is produced but it is empty:
![image](https://user-images.githubusercontent.com/7256543/159897135-ca01dc25-f9d1-4fb0-92a8-7e85088694b9.png)

Is there a command I'm missing to inline the images? 

Thanks for the quick reply!
hongooi73 commented 2 years ago

Yeah this looks pretty messy. For now I think the best bet is to just avoid using inline images. If you have a doc that has these, a workaround is to zip it up and send that instead.

twood886 commented 2 years ago

@Tom271 You need to set it to names(object$images)[[i]]

I cloned, changed that one line and it works now for multiple images

edit: @hongooi73 here is the simple fix to this issue. Works fine now Line 22 in c2762e3

MJPeyton commented 1 year ago

@hongooi73 any luck in getting this fix implemented?

Edit: Sorry, I see it in the inline-image branch

vorpalvorpal commented 1 year ago

I think there is something more going on here. I cloned the repo and changed line 22 of make_email_attachments.R to names(object$images)[[i]] but the images still don't render. Looking at the created message I get the following:

[...]

--_000_MEYPR01MB76973539954657D31D0AC6A3D21B9MEYPR01MB7697ausp_
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

foobar
[cid:img1.png]

foobar

[...]

--_000_MEYPR01MB76973539954657D31D0AC6A3D21B9MEYPR01MB7697ausp_
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: quoted-printable

<html xmlns:v=3D"urn:schemas-microsoft-com:vml" xmlns:o=3D"urn:schemas-micr=
osoft-com:office:office" xmlns:w=3D"urn:schemas-microsoft-com:office:word" =
xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" xmlns=3D"http:=
//www.w3.org/TR/REC-html40">

<p><span style=3D"font-size:10.5pt;font-family:&quot;Helvetica&quot;,sans-s=
erif;color:black">
foobar
</span></p>
<div>
<p class=3D"MsoNormal"><span style=3D"font-size:10.5pt;font-family:&quot;He=
lvetica&quot;,sans-serif;color:black">

<img width=3D"32" height=3D"32" style=
=3D"width:.3333in;height:.3333in" id=3D"_x0000_i1025" src=3D"cid:5A7EDD04DD=
5ADF45AD002F299D50D6D0@ausprd01.prod.outlook.com">

</span><span style=3D"fon=
t-size:10.5pt;font-family:&quot;Helvetica&quot;,sans-serif"><o:p></o:p></sp=
an></p>
<p class=3D"caption"><span style=3D"font-size:10.5pt;font-family:&quot;Helv=
etica&quot;,sans-serif;color:black">foobar</span><span st=
yle=3D"font-size:10.5pt;font-family:&quot;Helvetica&quot;,sans-serif"><o:p>=
</o:p></span></p>

[...]

--_000_MEYPR01MB76973539954657D31D0AC6A3D21B9MEYPR01MB7697ausp_--
--_004_MEYPR01MB76973539954657D31D0AC6A3D21B9MEYPR01MB7697ausp_
Content-Type: image/png; name="img1.png"
Content-Description: img1.png
Content-Disposition: inline; filename="img1.png"; size=144224; creation-date="Tue, 06 Dec 2022 02:46:03 GMT"; modification-date="Tue, 06 Dec 2022 02:46:03 GMT"
Content-Transfer-Encoding: base64

So the email has the image attached correctly as "img1.png" and the plain text correctly references this, but the html references "cid:5A7EDD04DD=5ADF45AD002F299D50D6D0@ausprd01.prod.outlook.com" instead of cid:img1.png. @twood886 's fix correctly sets the 'name variable, so the problem is with whatever re-writes the html.

vorpalvorpal commented 1 year ago

OK,

After some further digging the API for attachments is described here. What is missing is contentId. So the following works correctly:

add_external_attachments.blastula_message <- function(object, email)
{
    for(a in object$attachments)
        email$add_attachment(a$file_path)

    for(i in seq_along(object$images))
    {
        if(!is_small_attachment(nchar(object$images[[i]])/0.74))  # allow for base64 bloat
        {
            warning("Inline images must be < 3MB; will be skipped", call.=FALSE)
            next
        }
        body <- list(
            `@odata.type`="#microsoft.graph.fileAttachment",
            contentBytes=object$images[[i]],
            contentId=names(object$images)[[i]],
            name=names(object$images)[[i]],
            contentType=attr(object$images[[i]], "content_type"),
            isInline=TRUE
        )

        email$do_operation("attachments", body = body, http_verb = "POST")
    }
}

This corrects body$name to be names(object$images)[[i]] (as spotted by @twood886 ) and also adds the line contentId=names(object$images)[[i]],. I assume the same should also be added for the other methods of add_external_attachments.

I know I should do a pull request or something, but I'm still far too confused by git to do that sort of thing.

vorpalvorpal commented 1 year ago

Are there any plans to add the bugfix I provided above into the next version of Microsoft365R?

hongooi73 commented 1 year ago

Sorry for the delay in getting back to this. @vorpalvorpal I've added your fix in the inline-image-2 branch. Can you give it a try?

I ran into a problem with @Tom271 's example blastula email; the image doesn't render even in my local R session in VSCode. Instead of a pic, it just shows

![](c:/Rtemp/RtmpSqeCod/email61bc75617b04_files/figure-html/unnamed-chunk-1-1.png)<!-- -->

where the png file doesn't exist. Hopefully this is just a glitch in my local setup.

hongooi73 commented 1 year ago

To install the fix:

install_github("Azure/Microsoft365R@inline-image-2")
hongooi73 commented 1 year ago

Looks like the glitch has gone away, and multiple images works:

---
title : "Test"
output:
  html_fragment:
    fig_retina: 1
---
# Example text 
Test blastula mail

    ```{r}

    library(tidyverse)
    library(ggplot2)

    data(mtcars)
    mtcars %>% ggplot() + geom_line(aes(x=mpg, y=hp))

Example text after where the image should be placed

```{r}

library(tidyverse)
library(ggplot2)

data(mtcars)
mtcars %>% ggplot() + geom_line(aes(x=mpg, y=wt))
```

Example text 2



In Gmail:

![image](https://github.com/Azure/Microsoft365R/assets/11328890/b39e11e1-131c-4086-8598-cd686cee590f)

Many thanks for the fix @vorpalvorpal !