Android: How do I attach a temporary, generated image to an email?
Asked Answered
H

3

16

I have a programmatically generated image that I want to send as an attachment via the ACTION_SEND and EXTRA_STREAM method.

But how do i do this?

My first attempt (writing to my context.getCacheDir() based file path) appeared to work in the Gmail preview (no image preview, but attached file name and icon was visible), but the attachment never arrived on the recipient side. I guess this has something to do with permissions on the generated file, but how to avoid this? Do I need to set more permissive settings on these generated files (so that the Gmail activity can access)? Is that even possible for the app's cache folder?

Is there another file location that would be more suitable to write my files to? I considered the downloads folder, but think it would be an awkward location for something that only needs to exist until it has been emailed.

I have even tried encoding my image purely in a data:image/png;base64,ABCD... style URI. This, too, showed up in Gmail preview (attachment icon, but no file name), but did not result in a recipient-side attachment.

Has anyone been able to attach a one-shot generated image to an email intent by any means? What options may I have overlooked?

Helmand answered 25/8, 2010 at 23:8 Comment(0)
H
19

My problem really consisted of two parts:

  1. context.getCacheDir() is private to your app. You can't put something there and expect another app to be able to access it.
  2. I misunderstood what MIME type I should have been using. Even though I was sending email text, I really needed to specify image/png for the sake of my attachment.

Additionally, research indicated that putting (potentially large) images on the primary memory was not a good idea, even if you were going to immediately clean it up.

Once I did these things and wrote my generated images to a public location on the SD Card, it worked just fine.

So, in overview:

Request SD Card Access in your manifest

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Make sure SD Card is available

if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) 
{
    //Bail gracefully
}

Create a directory on the SD Card

File pngDir = new File(
    Environment.getExternalStorageDirectory(),   
    //Loose convention inferred from app examples
    "Android/data/com.somedomain.someapp/flotsam");

if (!pngDir.exists())
    pngDir.mkdirs();

Write your file to that directory and capture the Uri

File pngFile = new File(pngDir, "jetsam.png");
//Save file encoded as PNG
Uri pngUri = Uri.fromFile(pngFile);

Build an ACTION_SEND intent

Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setType("image/png"); //
intent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] { "[email protected]" });
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Portable Network Graphics");
intent.putExtra(android.content.Intent.EXTRA_CC, new String[] { "[email protected]" });
intent.putExtra(Intent.EXTRA_TEXT, "Something textual");
intent.putExtra(Intent.EXTRA_STREAM, pngUri);

And then start the activity

context.startActivity(Intent.createChooser(intent, "Something Pithy"));

And then make sure you clean everything up...

Caveat 1

There appears to be more support coming for app-specific SD Card directories, but alas, not in my required SDK version.

Caveat 2

This is an overview of the solution that eventually worked for me. It is not necessarily a "best practice" approach.

Caveat 3

This does mean that the application has to have an SD Card mounted in order to have the image attachments feature available, but this was totally acceptable for my use case. Your mileage may vary. If the SD Card is not available, I append a friendly note to the email explaining why the images could not be attached and how to rectify the situation.

Helmand answered 27/8, 2010 at 16:58 Comment(5)
Could this be done with a custom ContentProvider. It won't require an extra permission, and also remove dependency on SD card.Dempster
@Dempster can you elaborate on this possibility with an answer? I'd love to see more detail on how this can be done...Helmand
this solution dont works for me. most strange thing is that images file is created on sd card!Choroiditis
@Choroiditis what version(s) of android are you targeting? It has been a while since I was using this solution...Helmand
target is 4.1 @devfuel . min sdk 2.0, max 4.1, target 4.1Choroiditis
G
4

I've just run into exactly the same issue (wanting to attach a text file in my case). If you look in the Android log, the reason for it is:

02-28 21:01:28.434: E/Gmail(19673): file:// attachment paths must point to file:///mnt/sdcard. Ignoring attachment file:///data/data/com.stephendnicholas.gmailattach/cache/Test.txt

As a workaround (as mentioned by HRJ), you can use a ContentProvider to provide access to files in your application's internal cache so that Gmail can attach them. I've just written up a blog post on how to do it.

Hopefully that's of some help :)

Giddings answered 28/2, 2012 at 22:22 Comment(1)
ContentProvider was the solution I went with. I didn't want everyone to be able to read my files from the SD card.Foah
C
-1
tableLayout.buildDrawingCache();
        Bitmap test = Bitmap.createBitmap(tableLayout.getDrawingCache());
        tableLayout.destroyDrawingCache();

        Log.d("Image", test.toString());

        String path = Environment.getExternalStorageDirectory().toString(); 
        Log.d("Path", path);
        File file = new File(path,"mail_image.png");
        Uri pngUri = Uri.fromFile(file);
        Log.d("Real Image Path", pngUri.toString());

        Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
        emailIntent.setType("image/png");
        emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, "email to"); 
        emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,"Subject"); 
        emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "From My App"); 
                    emailIntent.putExtra(android.content.Intent.EXTRA_STREAM, pngUri );

        startActivity(Intent.createChooser(emailIntent, "Send mail..."));
Colucci answered 30/4, 2013 at 22:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.