How to open Email program via Intents (but only an Email program)

Android

Android Problem Overview


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?

Android Solutions


Solution 1 - Android

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.

Solution 2 - Android

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");

Solution 3 - Android

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[] {"[email protected]"});
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..."));

Solution 4 - Android

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[]{"[email protected]"});
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...

Solution 5 - Android

Try this one

Intent intent = new Intent("android.intent.action.SENDTO", Uri.fromParts("mailto", "[email protected]", null));
intent.putExtra("android.intent.extra.SUBJECT", "Enter Subject Here");
startActivity(Intent.createChooser(intent, "Select an email client")); 

Solution 6 - Android

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:[email protected]" +
    "?cc=" + "[email protected]" +
    "&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.

Solution 7 - Android

Try changing the MIME type from plain to message

intent.setType("text/message");

Solution 8 - Android

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

intent.setType("plain/text"); //Instead of "text/plain"

Solution 9 - Android

try this option:

Intent intentEmail = new Intent(Intent.ACTION_SEND);
intentEmail.setType("message/rfc822");

Solution 10 - Android

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

Uri uri = Uri.parse("mailto:"+ "[email protected]" +"?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

Solution 11 - Android

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDan LewView Question on Stackoverflow
Solution 1 - AndroidDan LewView Answer on Stackoverflow
Solution 2 - AndroidJeff SView Answer on Stackoverflow
Solution 3 - AndroidHaris ur RehmanView Answer on Stackoverflow
Solution 4 - AndroididolizeView Answer on Stackoverflow
Solution 5 - AndroidAshishView Answer on Stackoverflow
Solution 6 - Androiduser10496632View Answer on Stackoverflow
Solution 7 - AndroidBadSkillzView Answer on Stackoverflow
Solution 8 - AndroidPeterdkView Answer on Stackoverflow
Solution 9 - AndroidAshish JaiswalView Answer on Stackoverflow
Solution 10 - AndroidSateerView Answer on Stackoverflow
Solution 11 - AndroidAyyappaView Answer on Stackoverflow