84

I want to setup a part of my application that allows users to send a quick email to another user. It's not very hard to set this up:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, message);
Intent mailer = Intent.createChooser(intent, null);
startActivity(mailer);

However, the problem is that the ACTION_SEND is accepted by more than just email programs - for example, on my phone the Facebook app, Twitter, reddit is fun, and even Bluetooth come up as viable alternatives for sending this message. The message is entirely too long for some of these (especially Twitter).

Is there a way to limit the chooser to just applications that support long messages (such as email)? Or is there a way to detect the app that the user has chosen and adjust the message appropriately?

Dan Lew
  • 85,990
  • 32
  • 182
  • 176
  • 2
    I am wondering how Linkify class decides what to open up for mailto links. Maybe check the source code of Linkify, and post your findings. – Pentium10 Jul 22 '10 at 19:24
  • Good call - I'll check that out and let you know if I find anything of interest. – Dan Lew Jul 22 '10 at 19:27
  • Thanks again Pentium10, good suggestion on looking up how Linkify does things. – Dan Lew Jul 22 '10 at 19:59

11 Answers11

100

Thanks to Pentium10's suggestion of searching how Linkify works, I have found a great solution to this problem. Basically, you just create a "mailto:" link, and then call the appropriate Intent for that.:

Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.parse("mailto:?subject=" + subject + "&body=" + body);
intent.setData(data);
startActivity(intent);

There are a few interesting aspects to this solution:

  1. I'm using the ACTION_VIEW action because that's more appropriate for a "mailto:" link. You could provide no particular action, but then you might get some unsatisfactory results (for example, it will ask you if you want to add the link to your contacts).

  2. Since this is a "share" link, I am simply including no email address - even though this is a mailto link. It works.

  3. There's no chooser involved. The reason for this is to let the user take advantage of defaults; if they have set a default email program, then it'll take them straight to that, bypassing the chooser altogether (which seems good in my mind, you may argue otherwise).

Of course there's a lot of finesse I'm leaving out (such as properly encoding the subject/body), but you should be able to figure that out on your own.

Dan Lew
  • 85,990
  • 32
  • 182
  • 176
88

Changing the MIME type is the answer, this is what I did in my app to change the same behavior. I used intent.setType("message/rfc822");

gprathour
  • 14,813
  • 5
  • 66
  • 90
Jeff S
  • 3,256
  • 1
  • 18
  • 7
29

This worked for me

Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
emailIntent.setType("vnd.android.cursor.item/email");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {"abc@xyz.com"});
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "My Email Subject");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "My email content");
startActivity(Intent.createChooser(emailIntent, "Send mail using..."));
Haris ur Rehman
  • 2,593
  • 30
  • 41
  • 1
    Worked Like a charm.. Specially Note that the Extra_Email should be in String array, Or the To: will be empty... – Nilesh Aug 04 '15 at 19:58
4

Have you tried including the Intent.EXTRA_EMAIL extra?

Intent mailer = new Intent(Intent.ACTION_SEND);
mailer.setType("text/plain");
mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"name@email.com"});
mailer.putExtra(Intent.EXTRA_SUBJECT, subject);
mailer.putExtra(Intent.EXTRA_TEXT, bodyText);
startActivity(Intent.createChooser(mailer, "Send email..."));

That may restrict the list of available receiver applications...

idolize
  • 6,455
  • 4
  • 24
  • 34
  • 2
    I have tried this, doesn't help. Extras aren't used to filter the apps in a chooser. – Dan Lew Jul 22 '10 at 19:20
  • I think the only other solution would be to launch a specific mail program by passing a String with it's full class/package path. This would restrict your users to one Mail app, but it would prevent other types of apps (like Twitter) from being options... – idolize Jul 22 '10 at 19:29
  • 1
    I don't like that idea at all because most users will have two default Mail apps to begin with (the standard Mail app and Gmail), and I don't want to guess which one they use. – Dan Lew Jul 22 '10 at 19:34
  • I have 4 email clients, and barely use Gmail and Mail app. – Pentium10 Jul 22 '10 at 19:46
3

Try this one

Intent intent = new Intent("android.intent.action.SENDTO", Uri.fromParts("mailto", "yourmail@gmail.com", null));
intent.putExtra("android.intent.extra.SUBJECT", "Enter Subject Here");
startActivity(Intent.createChooser(intent, "Select an email client")); 
Ashish
  • 75
  • 7
3

None of the solutions worked for me. Thanks to the Open source developer, cketti for sharing his/her concise and neat solution.

String mailto = "mailto:bob@example.org" +
    "?cc=" + "alice@example.com" +
    "&subject=" + Uri.encode(subject) +
    "&body=" + Uri.encode(bodyText);

Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse(mailto));

try {
  startActivity(emailIntent);
} catch (ActivityNotFoundException e) {
  //TODO: Handle case where no email app is available
}

And this is the link to his/her gist.

user10496632
  • 463
  • 4
  • 13
0

try this option:

Intent intentEmail = new Intent(Intent.ACTION_SEND);
intentEmail.setType("message/rfc822");
Sujay
  • 2,510
  • 2
  • 27
  • 47
Ashish Jaiswal
  • 804
  • 1
  • 9
  • 23
0

Try changing the MIME type from plain to message

intent.setType("text/message");
BadSkillz
  • 1,993
  • 19
  • 37
0

I have tried many solutions, but most of them didn't work. It worked for android 12

Uri uri = Uri.parse("mailto:"+ "email@email.com" +"?subject="+ "Email Subject" +"&body="+ "Email Body");

            startActivity(new Intent(Intent.ACTION_VIEW, uri));

I have tried Intent.ACTION_SEND and Intent.ACTION_SENDTO, but non of these worked on android 12

Sarwar Sateer
  • 395
  • 3
  • 16
-1

This is a bit of a typo, since you need to switch your mimetype:

intent.setType("plain/text"); //Instead of "text/plain"
Peterdk
  • 15,625
  • 20
  • 101
  • 140
  • 2
    To the best of my knowledge, `plain/text` is not a valid MIME type. Do you have a reference for this? – Thomas Oct 26 '19 at 14:47
-1

SEND TO EMAIL CLIENTS ONLY - WITH MULTIPLE ATTACHMENTS

There are many solutions but all work partially.

mailto properly filters email apps but it has the inability of not sending streams/files.

message/rfc822 opens up hell of apps along with email clients

so, the solution for this is to use both.

  1. First resolve intent activities using mailto intent
  2. Then set the data to each activity resolved to send the required data
private void share()
{
     Intent queryIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
     Intent dataIntent  = getDataIntent();

     Intent targetIntent = getSelectiveIntentChooser(context, queryIntent, dataIntent);
     startActivityForResult(targetIntent);
}

Build the required data intent which is filled with required data to share

private Intent getDataIntent()
{
        Intent dataIntent = buildIntent(Intent.ACTION_SEND, null, "message/rfc822", null);

        // Set subject
        dataIntent.putExtra(Intent.EXTRA_SUBJECT, title);

        //Set receipient list.
        dataIntent.putExtra(Intent.EXTRA_EMAIL, toRecipients);
        dataIntent.putExtra(Intent.EXTRA_CC, ccRecipients);
        dataIntent.putExtra(Intent.EXTRA_BCC, bccRecipients);
        if (hasAttachments())
        {
            ArrayList<Uri> uris = getAttachmentUriList();

            if (uris.size() > 1)
            {
                intent.setAction(Intent.ACTION_SEND_MULTIPLE);
                dataIntent.putExtra(Intent.EXTRA_STREAM, uris);
            }
            else
            {
                dataIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris.get(0));
            }
        }

        return dataIntent;
}

protected ArrayList<Uri> getAttachmentUriList()
{
        ArrayList<Uri> uris = new ArrayList();
        for (AttachmentInfo eachAttachment : attachments)
        {
            uris.add(eachAttachment.uri);
        }

        return uris;
}

Utitlity class for filtering required intents based on query intent

// Placed in IntentUtil.java
public static Intent getSelectiveIntentChooser(Context context, Intent queryIntent, Intent dataIntent)
{
        List<ResolveInfo> appList = context.getPackageManager().queryIntentActivities(queryIntent, PackageManager.MATCH_DEFAULT_ONLY);

        Intent finalIntent = null;

        if (!appList.isEmpty())
        {
            List<android.content.Intent> targetedIntents = new ArrayList<android.content.Intent>();

            for (ResolveInfo resolveInfo : appList)
            {
                String packageName = resolveInfo.activityInfo != null ? resolveInfo.activityInfo.packageName : null;

                Intent allowedIntent = new Intent(dataIntent);
                allowedIntent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
                allowedIntent.setPackage(packageName);

                targetedIntents.add(allowedIntent);
            }

            if (!targetedIntents.isEmpty())
            {
                //Share Intent
                Intent startIntent = targetedIntents.remove(0);

                Intent chooserIntent = android.content.Intent.createChooser(startIntent, "");
                chooserIntent.putExtra(android.content.Intent.EXTRA_INITIAL_INTENTS, targetedIntents.toArray(new Parcelable[]{}));
                chooserIntent.addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION);

                finalIntent = chooserIntent;
            }

        }

        if (finalIntent == null) //As a fallback, we are using the sent data intent
        {
            finalIntent = dataIntent;
        }

        return finalIntent;
}
Ayyappa
  • 1,876
  • 1
  • 21
  • 41