Send an Email with created PDF

Please provide the following:

  1. SDK Version: 47.0
  2. Platforms(mostly Android)

I need some help on how to send an Email with a created PDF via Expo and Nodemailer.

I have my Backend Function for the NodeMailer setup and tested to actually work.

In the Frontend I have tried few different Expo Packages but always had something that would not work for me.

How I want it to work is:

  1. On Button Press open the created PDF
  2. When the user wants he can close the File
  3. In the Background send that opened File via my NodeMailer

What I’ve tried:

 await Print.printAsync({
   html,
   orientation: "portrait",
   printerUrl: this.state.selectedPrinter?.url, 
 })

This creates my File and I can save it as PDF! Now this would actually work for me if I could automatically rename the File. When I press save as PDF it is called “Document” but I need to have it named dynamically. I guess if I could rename it I might be able to pick it somehow and send it (like Expo DocumentPicker or FileSystem maybe).

Second approach is to save the File and then open it:

const { uri } = await Print.printToFileAsync({ html });
console.log('File has been saved to:', uri);

try {

  const cUri = await FileSystem.getContentUriAsync(uri);
             
  await ExpoIntent.startActivityAsync("android.intent.action.VIEW", {
      data: cUri,
      flags: 1,
      type: "application/pdf",
  });
}catch(e){
    console.log(e.message);
}

The Code saves my File and opens it up again. Now here is a URI I can access which looks kinda like this:

file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540xyyxwyx%252FPXXXX/Print/eb03cc8c-9c29-4d08-aed8-f10eXXX87fe5.pdf

When I try to use that URI and send it via nodemailer it tells me that the file does not exist!

Error Mail: Error: ENOENT: no such file or directory, open 'C:\Dev\Programmierung\rn\xxx-Server\file:\data\user\0\host.exp.exponent\cache\ExperienceData\%2540xxyx%252Fxxx\Print\cbcff690-d608-4138-a635-93cxxy72a2ed.pdf'

Which makes sense since that file is not available on my PC, its only inside my Emulator. How do I tell Expo the correct URI Link?

So whats important (one of the two):

  1. Renaming the File and save it under the correct name
  2. using the correct URI

I also had some approaches renaming the File using Expo Filesystem and Expo Sharing but not really the way I wanted it. If anyone could give some advice on how to achieve this would be great, or even different approaches with Expo DocumentPicker for example.

@wodin Hey Michael, will there be any updates on this? I really need to know how to use the created File, rename it and send it via nodemailer in “one go”.

A note: I think I can kinda rename the File with this:

const response = await Print.printToFileAsync({
html,
orientation: “portrait”,
printerUrl: this.state.selectedPrinter?.url, // iOS only
})

const pdfName = `${response.uri.slice(
  0,
  response.uri.lastIndexOf("/") + 1 
)}Monatsbericht_${Moment(this.state.actDate).format("MM-YYYY")}_User_Name_GXXX.pdf`

console.log("PDF_new_URI: " + pdfName);

await FileSystem.moveAsync({
  from: response.uri,
  to: pdfName
})
.then(res => console.log("Resultz: " + res))
.catch(err => console.log("Err On moveAsync " + err))

Because the console log actually gives me the desired Filename!

PDF_new_URI:

file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540yesiamfaded%252FXXX/Print/Monatsbericht_12-2022_User_Name_GXXX.pdf

However I cant seem to find that File on my Device after that and also when I pass the URI (of a example PDF) with DocumentPicker to my Nodemailer Function it tells me that it cant find the File, which makes sence because instead of sending it from the Emulator, Nodemailer trys to look for the FIle inside the Project Structure. Bascially searching for C./Users/Programmstructure/filepathOfURI/…
It should look directly into the Emulator Device Structure since the PDF will be saved on the Phone…

Hi @yesiamfaded

Please note: I am just an Expo user like you.

OK, I think you need to break this down into a few separate steps and solve each one before moving on to the next. e.g.:

  • Create the PDF (you’d need to get the URI of the file so you can send it to your server.)
  • Upload the PDF to your server
    • Server side: you need to be able to accept the uploaded file
    • Client side: you need to use something like fetch to upload the file from the app
  • Send a file via Nodemailer

I haven’t tried using the Print API before, but wouldn’t it be better to use printToFileAsync()? That should return the resulting file’s URI: FilePrintResult

Then you can upload the file using e.g. fetch, or possibly something like react-native-background-upload (although the Expo instructions are out of date. It looks like it should work out of the box with Expo, as long as you create a dev build and use that instead of Expo Go.)

Sending the file using Nodemailer: This part has nothing to do with Expo/React Native. As long as you were able to upload the file to your server, it’s now the server’s problem. So you’d need to check the Nodemailer docs to see how to do that part.

Hi @wodin, damn I didnt even know that you are not part of the team - sry about that. Yeah I am still struggling with the damn URI :sweat_smile:

But maybe if you have the time you could look into my SO Question, maybe you or other people had similar questions. node.js - Nodemailer changes URI before Mail is send - ENOENT: no such file or directory - Stack Overflow

Have a good day!

Hi. It looks like you are posting the URI (which is just a string that says where the file exists on the emulator) to your server, instead ulof actually uploading the file contents to your server.

If your server tries to read the file at that location, of course it will not find it, because it’s not on the server. The server probably doesn’t even have a /data directory, or /data/user, etc.

Perhaps it would be better to write small “building blocks” to make sure each intermediate step is working before tying them together.

E.g. make sure you can upload a file to the server and save it to disk. Then write a function to attach a local file to an email. Test those separately. Then tie them together to receive the file from the app and attach it to an email.