Android - not able to attach a file in email

2019-01-11 19:46发布

By default, files saved to the internal storage are private to your application and other applications cannot access them (nor can the user).

I am able to see the file "/data/data/package_name/files/ in file explore in DDMS, but when i attached the above file URI using imageUri in email , then i saw that attached file is of 0kb. i have used the default email APIs of Android.

Can anyone suggest me ,how to attach a file in email that is private to the application?

although i am successful able to save the file in SD card and attaching the file from SD card , this is working fine.

But if SD card is not available and saving the file to the internal storage , then how can i attach them in email.

String FILENAME = "hello_file.txt";
String string = "hello world!";FileOutputStream fos = openFileOutput(FILENAME,     Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();

File imageFile = getFileStreamPath(FILENAME );
Uri imageUri = Uri.fromFile(imageFile);

final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("*/*");
emailIntent.putExtra(android.content.Intent.EXTRA_STREAM,imageUri);

this.startActivityForResult(Intent.createChooser(emailIntent, "Send mail..."),SUB_ACTIVITY);

7条回答
倾城 Initia
2楼-- · 2019-01-11 19:59

I was facing the same issue and following worked for me.

First send Broadcast to notify device that file is created / mounted.

For example:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse("file://"+storagePath)));

Then use code to send mail with attachment.

Intent email = new Intent(Intent.ACTION_SEND);
email.putExtra(Intent.EXTRA_EMAIL,  "Receiver Email Address" );
email.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
email.putExtra(Intent.EXTRA_SUBJECT, "Subject");
email.putExtra(Intent.EXTRA_TEXT,"Email Text");

//Mime type of the attachment (or) u can use sendIntent.setType("*/*")
//email.setType("text/plain");
email.setType("application/YourMimeType");

//Full Path to the attachment
email.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://"+storagePath));
try
{
    startActivity(Intent.createChooser(email, "Send Message..."));
}
catch (android.content.ActivityNotFoundException ex) 
{

}
查看更多
贼婆χ
3楼-- · 2019-01-11 20:07

I have also experienced this problem using internal files and although I have used openFileInput with MODE_WORLD_READABLE on /data/data//files/testFileName.txt and used the URI.parse with the extra "/" (see below), the received test emailed is still lacking the desired attachment. So sorry but there is no answer, except try to use External files on the SD Card - which is my next experiment!

Code :

File tmpFile = new File(context.getFilesDir(), mfileName);
        Log.d(TAG, tmpFile.toString());  
// This shows: /data/data/org.eddiem.adeveloper.flatfiletest/files/testFile.csv 
        //File tmpFile2 = new File(context.getFileStreamPath(mfileName), mfileName);
        //Log.v(TAG, tmpFile2.toString());
// This also shows: /data/data/org.eddiem.adeveloper.flatfiletest/files/testFile.csv 

        //Uri uri = Uri.fromFile(new File(context.getFileStreamPath(mfileName), mfileName));
        Uri uri = Uri.parse("file://" + tmpFile.toString()); 
        //Uri uri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), 
        //                              mfileName));
        Log.d(TAG, "Uri-path is: " + uri.getPath()); // or .toString()

        Intent i = new Intent(android.content.Intent.ACTION_SEND);
        i.setType("text/plain");
        i.putExtra(Intent.EXTRA_EMAIL, new String[]{"eddie.moxey@sky.com"});
        i.putExtra(Intent.EXTRA_SUBJECT, "Test Email - with Attachment");
        i.putExtra(Intent.EXTRA_TEXT, "This is a test Email with an Attachment.");
        i.putExtra(Intent.EXTRA_STREAM, uri);
        //startActivity(Intent.createChooser(i, "Select application"));
        startActivity(Intent.createChooser(i, "Send mail"));
查看更多
劫难
4楼-- · 2019-01-11 20:08

Try using Context.MODE_WORLD_READABLE instead of Context.MODE_PRIVATE when saving the file. Then other apps will have access to the file.

查看更多
▲ chillily
5楼-- · 2019-01-11 20:10
Android: Attaching files from internal cache to Gmail




package com.stephendnicholas.gmailattach; 

import java.io.File; 
import java.io.FileNotFoundException; 

import android.content.ContentProvider; 
import android.content.ContentValues; 
import android.content.UriMatcher; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.ParcelFileDescriptor; 
import android.util.Log; 

public class CachedFileProvider extends ContentProvider { 

    private static final String CLASS_NAME = "CachedFileProvider"; 

    // The authority is the symbolic name for the provider class 
    public static final String AUTHORITY = "com.stephendnicholas.gmailattach.provider"; 

    // UriMatcher used to match against incoming requests 
    private UriMatcher uriMatcher; 

    @Override
    public boolean onCreate() { 
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 

        // Add a URI to the matcher which will match against the form 
        // 'content://com.stephendnicholas.gmailattach.provider/*' 
        // and return 1 in the case that the incoming Uri matches this pattern 
        uriMatcher.addURI(AUTHORITY, "*", 1); 

        return true; 
    } 

    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode) 
            throws FileNotFoundException { 

        String LOG_TAG = CLASS_NAME + " - openFile"; 

        Log.v(LOG_TAG, 
                "Called with uri: '" + uri + "'." + uri.getLastPathSegment()); 

        // Check incoming Uri against the matcher 
        switch (uriMatcher.match(uri)) { 

        // If it returns 1 - then it matches the Uri defined in onCreate 
        case 1: 

            // The desired file name is specified by the last segment of the 
            // path 
            // E.g. 
            // 'content://com.stephendnicholas.gmailattach.provider/Test.txt' 
            // Take this and build the path to the file 
            String fileLocation = getContext().getCacheDir() + File.separator 
                    + uri.getLastPathSegment(); 

            // Create & return a ParcelFileDescriptor pointing to the file 
            // Note: I don't care what mode they ask for - they're only getting 
            // read only 
            ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File( 
                    fileLocation), ParcelFileDescriptor.MODE_READ_ONLY); 
            return pfd; 

            // Otherwise unrecognised Uri 
        default: 
            Log.v(LOG_TAG, "Unsupported uri: '" + uri + "'."); 
            throw new FileNotFoundException("Unsupported uri: "
                    + uri.toString()); 
        } 
    } 

    // ////////////////////////////////////////////////////////////// 
    // Not supported / used / required for this example 
    // ////////////////////////////////////////////////////////////// 

    @Override
    public int update(Uri uri, ContentValues contentvalues, String s, 
            String[] as) { 
        return 0; 
    } 

    @Override
    public int delete(Uri uri, String s, String[] as) { 
        return 0; 
    } 

    @Override
    public Uri insert(Uri uri, ContentValues contentvalues) { 
        return null; 
    } 

    @Override
    public String getType(Uri uri) { 
        return null; 
    } 

    @Override
    public Cursor query(Uri uri, String[] projection, String s, String[] as1, 
            String s1) { 
        return null; 
    } 
}




<provider android:name="CachedFileProvider" android:authorities="com.stephendnicholas





public static void createCachedFile(Context context, String fileName, 
            String content) throws IOException { 

    File cacheFile = new File(context.getCacheDir() + File.separator 
                + fileName); 
    cacheFile.createNewFile(); 

    FileOutputStream fos = new FileOutputStream(cacheFile); 
    OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8"); 
    PrintWriter pw = new PrintWriter(osw); 

    pw.println(content); 

    pw.flush(); 
    pw.close(); 
}




public static Intent getSendEmailIntent(Context context, String email, 
            String subject, String body, String fileName) { 

    final Intent emailIntent = new Intent( 
                android.content.Intent.ACTION_SEND); 

    //Explicitly only use Gmail to send 
    emailIntent.setClassName("com.google.android.gm","com.google.android.gm.ComposeActivityGmail"); 

    emailIntent.setType("plain/text"); 

    //Add the recipients 
    emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, 
                new String[] { email }); 

    emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject); 

    emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body); 

    //Add the attachment by specifying a reference to our custom ContentProvider 
    //and the specific file of interest 
    emailIntent.putExtra( 
            Intent.EXTRA_STREAM, 
                Uri.parse("content://" + CachedFileProvider.AUTHORITY + "/"
                        + fileName)); 

    return emailIntent; 
}

    enter code here
查看更多
时光不老,我们不散
6楼-- · 2019-01-11 20:12

When you try to attach file from internal storage, GMail writes an error to the log:

ERROR/Gmail(...): file:// attachment paths must point to file:///mnt/sdcard. 

E-mail application would show you the attached file even if it didn't physically exist.

As for an external storage, documentation says that:

Every Android-compatible device supports a shared "external storage" that you can use to save files. This can be a removable storage media (such as an SD card) or an internal (non-removable) storage.

That means you don't have to worry about device not having an external storage at all. Still, external storage can be unavailable at times. Refer to http://developer.android.com/guide/topics/data/data-storage.html#filesExternal

查看更多
smile是对你的礼貌
7楼-- · 2019-01-11 20:17

In order to share a private file you need to use a ContentProvider to provide access to your file by other applications. Here's a great example: Android: Attaching files from internal cache to Gmail.

Also, although the tutorial mentions that you need to declare your provider in the Android manifest file, it does not specify that it should be contained in <application>, so make sure that when you declare it is within <application> </application>.

查看更多
登录 后发表回答