Skip to content
Advertisement

Android 11: Send e-mail with automatically attached file

I want open and email app with already generated text, subject, recipient and attached file, it works with android sdk version 29 (android 10) and lower. However starting Android 11 there are restriction to writing file in external or internal storages, and there is also another restriction that is not allowed to attach file automatically from app file directory. Previously I was copying from app storage to internal or external storage to attach file, any solutions?

done android:requestLegacyExternalStorage="true"

public static void sendMail(Context context) throws IOException {
        Context appContext = context.getApplicationContext();

        File logFile = FileUtils.createFile(context.getFilesDir().getAbsolutePath(), "testFile.txt", "Test");

        File logsDirectory = new File(FileUtils.getStorageDirectory(appContext), "files");
        logsDirectory.mkdirs();

        File destFile = new File(logsDirectory, "log.txt");

        InputStream in = new FileInputStream(logFile);
        boolean copied = FileUtils.copyToFile(in, destFile);

        Uri logPath = Uri.fromFile(destFile);

        Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
        emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        emailIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // set the type to 'email'
        emailIntent.setData(Uri.parse("mailto:"));
        String[] to = {"support@test.com"};
        String subject = "Test log";
        String body =
                "Hello";
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
        emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body);
        // the attachment
        emailIntent.putExtra(Intent.EXTRA_STREAM, logPath);

        context.startActivity(Intent.createChooser(emailIntent, "Send email..."));
    } 
public class FileUtils {
    
        public static String getExtensionFromFileName(String fileName) {
        if (fileName == null) return null;

        String extension = null;
        int i = fileName.lastIndexOf('.');
        if (i > 0) {
            extension = fileName.substring(i + 1);
        }
        return extension;
    }

    /**
     * Copy data from a source stream to destFile. Return true if succeed, return false if failed.
     */
    public static boolean copyToFile(InputStream inputStream, File destFile) {
        if (inputStream == null || destFile == null) return false;
        try {
            try (OutputStream out = new FileOutputStream(destFile)) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) >= 0) {
                    out.write(buffer, 0, bytesRead);
                }
            }
            return true;
        } catch (IOException e) {
            Log.e("[File Utils]", "copyToFile exception: " + e);

        }
        return false;
    }


    public static String getStorageDirectory(Context mContext) {
        String storageDir =
                Environment.getExternalStorageDirectory().getAbsolutePath()
                        + "/"
                        + mContext.getString(R.string.app_name);
        File file = new File(storageDir);
        mContext.getExternalMediaDirs();

        if (!file.isDirectory() || !file.exists()) {


        }
        return storageDir;
    }

    public static File createFile(String directory ,String fileName, String textToAttach)
    {
        File logFile = new File(directory  + "/" + fileName);
        if (!logFile.exists())
        {
            try
            {
                logFile.createNewFile();
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        try
        {
            //BufferedWriter for performance, true to set append to file flag
            BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
            buf.append(textToAttach);
            buf.newLine();
            buf.close();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return logFile;
    }
}

Answer

I have done using FileProvider and selector, this is for multiple files

public static void sendMail(Context context) {
        Context appContext = context.getApplicationContext();
        final String authority = appContext.getPackageName() + ".FileProvider";
        String[] to = {"test@test.com"};
        String subject = "subject";
        String body = "body";
        
        ArrayList<File> logFiles = getLogFile(context);

        if (logFiles.size() == 0) {
            Toast.makeText(
                            context,
                            context.getString(R.string.toast_send_failed_no_file_found),
                            Toast.LENGTH_LONG)
                    .show();
            return;
        }
        // has to be an ArrayList

        ArrayList<Uri> logPaths = new ArrayList<>();
        for (File file : logFiles) {
            if (file.exists()) {
                logPaths.add(FileProvider.getUriForFile(appContext, authority, file));
            }
        }

        Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
        emailSelectorIntent.setDataAndType(Uri.parse("mailto:"), "plain/text");

        final Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
        // emailIntent.setType("plain/text");
        emailIntent.addFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

        emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        emailIntent.putExtra(Intent.EXTRA_TEXT, body);
        emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, logPaths);
        emailIntent.setSelector(emailSelectorIntent);

        context.startActivity(Intent.createChooser(emailIntent, "Send Logs"));
    }
Advertisement