react-native-mail icon indicating copy to clipboard operation
react-native-mail copied to clipboard

Can't attach the file in email for the android mobile.

Open Sathiyamm opened this issue 6 years ago • 18 comments

I'm using the below code. It's working fine in the IOS mobile. But Not working in the Android mobile. An error shows the "permission denied for the attachment". After I'm change the path path:'file://'+DocumentDirectoryPath + '/Log.txt', That time an error shows the "can't attach the empty file" `sendMail = (issueType) => {

    Mailer.mail({
        subject: 'need help',
        recipients: ['[email protected]'],
        ccRecipients: ['[email protected]'],
        bccRecipients: ['[email protected]'],
        body: '<b>A Bold Body</b>',
        isHTML: true,
        attachment: {
            path: DocumentDirectoryPath + '/Log.txt',  // The absolute path of the file from which to read data.
            type: 'text',   // Mime Type: jpg, png, doc, ppt, html, pdf, csv"Fetchh_Log.txt"
            name: 'Log.txt',                 // Optional: Custom filename for attachment
        }
    }, (error, event) => {
      Alert.alert(
          error,
          event,
          [
            {text: 'Ok', onPress: () => console.log('OK: Email Error Response')},
            {text: 'Cancel', onPress: () => console.log('CANCEL: Email Error Response')}
          ],
          { cancelable: true }
        )
    });
}`

Any mistake in the above code? or any changes for android mobile?

Sathiyamm avatar Oct 10 '18 13:10 Sathiyamm

Hi I am currently facing this issue as well. Please help.

akshay2604 avatar Oct 30 '18 11:10 akshay2604

For anyone still struggling with this issue, it is no longer recommended to share data such as an attachment using the file:// scheme. The solution is to implement a FileProvider. It allows you to securely pass file defined through an intent.

Useful links

https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/en https://stackoverflow.com/questions/18249007/how-to-use-support-fileprovider-for-sharing-content-to-other-apps

Hope this helps

frodinm avatar Nov 10 '18 18:11 frodinm

+1

It's working fine in the iOS mobile. But not working in the Android Mobile.

recepkocur avatar Nov 19 '18 11:11 recepkocur

Hope this helps someone.

I had an issue attaching an image. Gmail would error with "unable to attach".

As I was using react-native-image-picker get the image, it was being returned via a content provider. The path would start content:/.

Creating a file from that path wasn't working. If you create a Uri directly from the path that was passed in, it worked.

      ReadableMap attachment = options.getMap("attachment");
      if (attachment.hasKey("path") && !attachment.isNull("path")) {
        String path = attachment.getString("path");
        Uri p = Uri.parse(path);
        i.putExtra(Intent.EXTRA_STREAM, p);
      }
    }

michaeljohndunn avatar Jan 07 '19 17:01 michaeljohndunn

You must save the image to device's picture directory.

import RNFS from "react-native-fs";

var destPath = RNFS.PicturesDirectoryPath + '/yourpicture.jpg'; RNFS.moveFile(data.uri, destPath) .then((success) => { console.log('file moved!'); }) .catch((err) => { console.log("Error: " + err.message); });

//then in your Mailer.mail attachment //the correct path should be /storage/emulated/0/Pictures/yourpicture.jpg

path: destPath

azizimusa avatar Feb 01 '19 19:02 azizimusa

You must save the image to device's picture directory.

import RNFS from "react-native-fs";

var destPath = RNFS.PicturesDirectoryPath + '/yourpicture.jpg'; RNFS.moveFile(data.uri, destPath) .then((success) => { console.log('file moved!'); }) .catch((err) => { console.log("Error: " + err.message); });

//then in your Mailer.mail attachment //the correct path should be /storage/emulated/0/Pictures/yourpicture.jpg

path: destPath

still has the error with "can not attach empty file." The source uri(data.uri) I am using was "file:///data/user/0/com.myapp/cache/mypicture.jpg", and the desPath is exactly what you mentioned. The moveFile function seems not work either. Could you help check? Thanks!

qiankf avatar Feb 12 '19 05:02 qiankf

You must save the image to device's picture directory. import RNFS from "react-native-fs"; var destPath = RNFS.PicturesDirectoryPath + '/yourpicture.jpg'; RNFS.moveFile(data.uri, destPath) .then((success) => { console.log('file moved!'); }) .catch((err) => { console.log("Error: " + err.message); }); //then in your Mailer.mail attachment //the correct path should be /storage/emulated/0/Pictures/yourpicture.jpg path: destPath

still has the error with "can not attach empty file." The source uri(data.uri) I am using was "file:///data/user/0/com.myapp/cache/mypicture.jpg", and the desPath is exactly what you mentioned. The moveFile function seems not work either. Could you help check? Thanks!

Have you check after you move the file does it success?

azizimusa avatar Feb 12 '19 06:02 azizimusa

You must save the image to device's picture directory. import RNFS from "react-native-fs"; var destPath = RNFS.PicturesDirectoryPath + '/yourpicture.jpg'; RNFS.moveFile(data.uri, destPath) .then((success) => { console.log('file moved!'); }) .catch((err) => { console.log("Error: " + err.message); }); //then in your Mailer.mail attachment //the correct path should be /storage/emulated/0/Pictures/yourpicture.jpg path: destPath

still has the error with "can not attach empty file." The source uri(data.uri) I am using was "file:///data/user/0/com.myapp/cache/mypicture.jpg", and the desPath is exactly what you mentioned. The moveFile function seems not work either. Could you help check? Thanks!

Uploading from cache folder wont work. You must move the file to picture directory. var destPath = RNFS.PicturesDirectoryPath + '/yourpicture.jpg';

I saw from PR 127 that after API Level 24, the exception will throw when an application exposes a file:// Uri to another app, and apps should use content:// Uris so the platform can extend temporary permission for the receiving app to access the resource. https://developer.android.com/reference/android/os/FileUriExposedException

What is the absolute path for RNFS.PicturesDirectoryPath? It seems a relative path.

qiankf avatar Feb 12 '19 06:02 qiankf

I have made a demo to send mail with photo as attachment.

https://github.com/azizimusa/react-native-mail-demo

azizimusa avatar Feb 12 '19 08:02 azizimusa

I have made a demo to send mail with photo as attachment.

https://github.com/azizimusa/react-native-mail-demo

Thank you so much for your answers! I will learn your demo code. May I ask which level of the SDK API in your device?

qiankf avatar Feb 12 '19 09:02 qiankf

Tested on Xiaomi MI5 Android 8.0 SDK 26

azizimusa avatar Feb 12 '19 09:02 azizimusa

I have a workaround. You need to use react-native-fs. The solution is to copy the file from the private app cache to the external storage which is readable by other apps.

    let path = pdfFilePath;
    if (Platform.OS !== 'ios') {
      try {
        let hasPermission = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
        if (!hasPermission) {
          const granted = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
            {
              title: i18n.t('write_storage_permission'),
              message: i18n.t('write_storage_permission_message'),
              buttonNegative: i18n.t('cancel'),
              buttonPositive: i18n.t('ok'),
            },
          );
          hasPermission = granted !== PermissionsAndroid.RESULTS.GRANTED;
        }
        if (!hasPermission) {
          handleError(i18n.t('error_accessing_storage'));
          return;
        }
      } catch (error) {
        console.warn(error);
      }

      path = `${RNFS.ExternalStorageDirectoryPath}/project_overview_${Number(new Date())}.pdf`;
      
      try {
        await RNFS.copyFile(pdfFilePath, path);
      } catch(error) {
        handleError(get(error, 'message', error));
        return;
      }
    }

    function handleError(error) {
      if (error === 'not_available') error = i18n.t('mail_not_available');
      Alert.alert(
        i18n.t('error'),
        error,
        [
          { text: i18n.t('ok') },
        ],
        { cancelable: true }
      )
    }
    Mailer.mail({
      subject: i18n.t('FinancingPlanning.loan_request_email_subject'),
      recipients: [],
      body: i18n.t('FinancingPlanning.loan_request_email_body', { name: get(user, 'profile.name', '') }),
      isHTML: true,
      attachment: {
        path,  // The absolute path of the file from which to read data.
        type: 'pdf',   // Mime Type: jpg, png, doc, ppt, html, pdf, csv
        name: 'project_overview.pdf',   // Optional: Custom filename for attachment
      }
    }, (error, event) => {
      if (error) {
        handleError(error);
      }
    });

brmk avatar Feb 27 '19 17:02 brmk

In case anyone is still looking for a solution, that's what finally worked in my case: https://github.com/marcinolek/react-native-mail/commit/384d3629d2fe23bc1ded25447cad3532f515030b

Inspired by PR 127 & https://stackoverflow.com/questions/18249007/how-to-use-support-fileprovider-for-sharing-content-to-other-apps

marcinolek avatar Sep 17 '19 21:09 marcinolek

@marcinolek Your fork works beautifully, thank you!

jeffmon avatar Oct 05 '19 20:10 jeffmon

Should really consider adding this to this repo.

fierysolid avatar Apr 03 '20 04:04 fierysolid

I had similar issue with attaching json file to mail. It just didn't appear in mail after sendMail func performed My solution was wrapping attachment file into array.

attachments: [{
  path: '',  // The absolute path of the file from which to read data.
  type: '',   // Mime Type: jpg, png, doc, ppt, html, pdf, csv 
  // mimeType - use only if you want to use custom type
  name: '',   // Optional: Custom filename for attachment
}] 

RN: 0.63 React: 16.9 react-native-mail: 6.0.0

dmko1610 avatar Feb 11 '21 07:02 dmko1610

And of course our team used RNFS for getting an absolute path

dmko1610 avatar Feb 11 '21 07:02 dmko1610

You must save the image to device's picture directory.

import RNFS from "react-native-fs";

var destPath = RNFS.PicturesDirectoryPath + '/yourpicture.jpg'; RNFS.moveFile(data.uri, destPath) .then((success) => { console.log('file moved!'); }) .catch((err) => { console.log("Error: " + err.message); });

//then in your Mailer.mail attachment //the correct path should be /storage/emulated/0/Pictures/yourpicture.jpg

path: destPath

worked like a charm, thanks @azizimusa

AndreiTimofte96 avatar Mar 09 '23 23:03 AndreiTimofte96