The user-defined CreateChooser can send mails with attachments.


When we need to send email in our application requirements. We usually do not implement an email App ourselves, but forward it to other apps through implicit Intent. We just need to add some corresponding data. The official Android document tells us that we can send email through the following three actions:

ACTION_SENDTO (for without accessories)
ACTION_SEND (for with one accessory)
ACTION_SEND_MULTIPLE `(for with multiple accessories)

Through the following combination of ACTION_SENDTO and "mailto:" the system will filter out all email apps for us.

public void composeEmail(String[] addresses, String subject) {
    Intent intent = new Intent(Intent.ACTION_SENDTO);
    intent.setData(Uri.parse("mailto:")); // only email apps should handle this
    intent.putExtra(Intent.EXTRA_EMAIL, addresses);
    intent.putExtra(Intent.EXTRA_SUBJECT, subject);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(Intent.createChooser(intent, "Send mail..."));

This is the effect we expect, however, when we want to add attachments. For example, the following code will pop up a lot of third-party software, including non email App, for us to choose from:

public void composeEmail(String[] addresses, String subject, Uri attachment) {
    Intent intent = new Intent(Intent.ACTION_SEND);
    intent.putExtra(Intent.EXTRA_EMAIL, addresses);
    intent.putExtra(Intent.EXTRA_SUBJECT, subject);
    intent.putExtra(Intent.EXTRA_STREAM, attachment);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(Intent.createChooser(intent, "Send mail..."));

Select the App we want by customizing CreateChooser

The above results are certainly not what we want. We hope that our application selection pop-up window is clean, and there will be no qq, wechat, file manager and other additional applications that can accept action ` send. The solution is to customize our own CreateChooser.
Method is the following code, which adds a detailed explanation.

public void sendLog(String email, String subject, Uri contentUri) {
      // The first step is to build an Intent with all the mail information added,
      // In theory, call the Intent to directly create the
      // There will be many alternative applications, including those we don't need.
      Intent emailIntent = new Intent(Intent.ACTION_SEND);
      emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{email});
      emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
      emailIntent.putExtra(Intent.EXTRA_STREAM, contentUri);

      // The second step is to create an action? SendTo and"mailto:"Combined Intent´╝î
      // And use this combination to find a collection of ResolveInfo that supports mail sending applications.
      // ResolveInfo is the information obtained by parsing the Intent filter in the manifest file.
      Intent queryIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
      List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentActivities(queryIntent,
              | PackageManager.GET_RESOLVED_FILTER);

       // The fourth step is to build our goal Intent, and through iterative resolveInfos,
       // Create all target Intent. These intents not only contain the information of emailIntent above,
       // At the same time, because Component is also set, it is equivalent to an Intent displayed,
       // So these intents are fixed.
      ArrayList<Intent> targetIntents = new ArrayList<>();
      for (ResolveInfo info : resolveInfos) {
        ActivityInfo ai = info.activityInfo;
        Intent intent = new Intent(emailIntent);
        intent.setComponent(new ComponentName(ai.packageName,;

      // Step 5: build CreateChooser through the target Intent set above.
      // targetIntents is required here.remove(0)Because,
      // When creating the Intent of the CreateChooser, the incoming Intent will be in it.
      // Therefore, you need to remove it from the collection. Otherwise, when you pass in the target Intent array through the way of extra initial Intent,
      // The first Intent will have one more.
      Intent chooser = Intent.createChooser(targetIntents.remove(0), subject);
          Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{}));

Tags: Android

Posted on Thu, 30 Apr 2020 08:48:20 -0700 by Scriptmaker