Android - not able to attach a file in email
Asked Answered
C

7

12

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);
Clear answered 8/11, 2010 at 11:34 Comment(5)
I faced the similar issue. From SD card that works just fine... But from internal storage I didn't succeed in this functionality. Maybe playing with MIME types will help to go on..Candidacandidacy
could you please elobrate it ?Clear
Personally I used the following code to send attached .html file: Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); emailIntent.setType("text/html"); emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "scor card"); File sdDir = Environment.getExternalStorageDirectory(); File file = new File(sdDir, Preferences.PATH_TO_SAVE_ON_SD_CARD + "/scoreHtml.html"); emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); context.startActivity(Intent.createChooser(emailIntent, "Email:"));Candidacandidacy
but in the above code, SD card is being used. i want to attach the image in email without storing it into SD card.Clear
Did you ever ran across a solution to this problem?Josephina
M
6

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

Martica answered 12/1, 2011 at 23:32 Comment(1)
Thank you! I couldn't figure out why it was failing and I didn't think to change the filters on my LogCat window.Nydianye
S
5
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
Shredding answered 15/1, 2013 at 10:30 Comment(1)
Exactly what I needed, but adding the source would be nice : stephendnicholas.com/archives/974 . I also found it useful as its a bit more structured.Scheld
T
4

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>.

Tolmann answered 10/3, 2012 at 8:49 Comment(0)
T
3

This Code may help you out to get idea about attachment:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    buttonSend = (Button) findViewById(R.id.buttonSend);

    textTo = (EditText) findViewById(R.id.editTextTo);
    textSubject = (EditText) findViewById(R.id.editTextSubject);
    textMessage = (EditText) findViewById(R.id.editTextMessage);

    buttonSend.setOnClickListener( new OnClickListener() {
        @Override
        public void onClick(View v) {
            String to = textTo.getText().toString();
            String subject = textSubject.getText().toString();
            String message = textMessage.getText().toString();

            Intent i = new Intent(Intent.ACTION_SEND);
            i.setType("plain/text");
            File data = null;

            try {
                Date dateVal = new Date();
                String filename = dateVal.toString();
                data = File.createTempFile("Report", ".csv");
                FileWriter out = (FileWriter) GenerateCsv.generateCsvFile(
                                                data, "Name,Data1");
                i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(data));
                i.putExtra(Intent.EXTRA_EMAIL, new String[] { to });
                i.putExtra(Intent.EXTRA_SUBJECT, subject);
                i.putExtra(Intent.EXTRA_TEXT, message);
                startActivity(Intent.createChooser(i, "E-mail"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });
}

public class GenerateCsv
{
    public static FileWriter generateCsvFile(File sFileName,String fileContent) 
    {
        FileWriter writer = null;

        try {
            writer = new FileWriter(sFileName);
            writer.append(fileContent);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return writer;
    }
}

The above code requires you add the following permission to your manifest file:

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
Tillie answered 13/7, 2012 at 14:34 Comment(0)
O
1

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

Opheliaophelie answered 8/11, 2010 at 11:41 Comment(1)
@ , i had already tried with MODE_WORLD_WRITEABLE, but it doesnt work.Clear
H
1

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[]{"[email protected]"});
        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"));
Healion answered 2/11, 2011 at 14:35 Comment(0)
G
0

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) 
{

}
Giffin answered 15/12, 2014 at 12:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.