Attaching file from internal storage to email

2019-04-07 14:04发布

问题:

Similar threads here do not have answers that helped... I want to create email message with file attach, file is on internal storage. Here is code:

Intent i = new Intent(Intent.ACTION_SEND);
    i.setType("text/plain");
    i.putExtra(Intent.EXTRA_EMAIL  , new String[]{email});
    i.putExtra(Intent.EXTRA_SUBJECT, "Smart Weight Tracker");
    i.putExtra(Intent.EXTRA_TEXT   , "CSV file is in attachment");

    Uri uri;
    if(useExternal){
        uri = Uri.fromFile(new File(this.getExternalFilesDir(null),fname));
    }
    else{
        File f = new File(this.getFilesDir(),fname);
        f.setReadable(true, false);
        f.setWritable(true, false);
        uri = Uri.fromFile(f);
    }

    i.putExtra(Intent.EXTRA_STREAM, uri);

    try {
        startActivity(Intent.createChooser(i, "Send mail..."));
    } catch (android.content.ActivityNotFoundException ex) {
        Toast.makeText(MainActivity.this, "There are no email clients installed.", Toast.LENGTH_SHORT).show();
    }

It works perfectly with external storage, but i have no attach when use internal storage. I checked - file opens, (it's length in my app by showing Toast - is OK, > 0).

I write it this way:

  OutputStreamWriter out =
                new OutputStreamWriter(con.openFileOutput(fname, Context.MODE_WORLD_READABLE));

In logcat i see

I/Gmail   (28480): >>>>> Attachment uri: file:///data/data/Android.MyApp/files     /31.10.2011.csv
I/Gmail   (28480): >>>>>           type: text/plain
I/Gmail   (28480): >>>>>           name: 31.10.2011.csv
I/Gmail   (28480): >>>>>           size: 0

Size == 0!

Any ideas?

回答1:

Hi, Try to use content providers.

emailIntent.putExtra(Intent.EXTRA_STREAM,Uri.parse("content://" + CachedFileProvider.AUTHORITY + "/"+ fileName)); 

........ 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.gmailattach.provider">

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; 
}

http://stephendnicholas.com/archives/974#comment-342



回答2:

Uri fileUri = Uri.fromFile(new File(context.getCacheDir()+ "/"+ fileName));                                           

Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,
                    "Test Subject");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT,
                    "go on read the emails");
emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri);

startActivity(emailIntent);

Please try this code. Hope this would help.



回答3:

I was following the stephendnicholas code for hours thinking I HAD to write my files to internal storage because my device had no sd card.

Creating my "internal" file like this worked just fine for me:

File file = new File(getExternalFilesDir(null), filename); // :)

It avoided Gmail limitations during attachment.

Before this I was creating my file object like this:

File file = new File(this.getFilesDir(), filename); //will not attach

But if your file is literally from internal storage, then stephendnicholas content providers etc. work if you have mad android skills.