46

I'm using Intent.ACTION_SEND to send an email. However, when I call the intent it is showing choices to send a message, send an email, and also to send via bluetooth. I want it to only show choices to send an email. How can I do this?

hichris123
  • 10,145
  • 15
  • 56
  • 70
Ganapathy C
  • 5,989
  • 5
  • 42
  • 75

17 Answers17

83

[Solution for API LEVEL >=15]

I've finally succeded in sending email WITH attachments to ONLY email clients. I write it here because it took me a lot of time and it may be usefull to others.

The problem is:

  • Intent.ACTION_SENDTO takes Data URI (so you can specify "mailto:" schema) BUT it does not accept Intent:EXTRA_STREAM.

  • Intent.ACTION_SEND accepts Intent:EXTRA_STREAM (so you can add attachment) BUT it takes only Type (not Data URI so you cannot specify "mailto:" schema).

So Intent.ACTION_SEND lets the user choose from several Activities, even if you setType("message/rfc822"), because that App/Activities can manage all file types (tipically GDrive/Dropbox Apps) and so even email message files.

The solution is in the setSelector method. With this method you can use Intent.ACTION_SENDTO to select the Activity, but then send the Intent.ACTION_SEND Intent.

Here my solution code (the attachment came from a FileProvider, but it could be any file):

{
    Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
    emailSelectorIntent.setData(Uri.parse("mailto:"));

    final Intent emailIntent = new Intent(Intent.ACTION_SEND);
    emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"address@mail.com"});
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
    emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    emailIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    emailIntent.setSelector( emailSelectorIntent );

    Uri attachment = FileProvider.getUriForFile(this, "my_fileprovider", myFile);
    emailIntent.putExtra(Intent.EXTRA_STREAM, attachment);

    if( emailIntent.resolveActivity(getPackageManager()) != null )
        startActivity(emailIntent);
}
ARLabs
  • 1,465
  • 1
  • 14
  • 25
  • Great, this it the only method that really works without compromises. – P1x Mar 05 '18 at 11:17
  • Bounty earned. nice answer, never really thought of combining the SEND and SENDTO with the selector. – Shark Feb 20 '20 at 17:28
  • I tried lots of different approaches and this one is by far the best. – Egis Apr 23 '20 at 10:48
  • I've spent a couple days trying to figure out what I had wrong. I think there were a couple things, but this answer is a good one. For me I believe it was a combination of not knowing I really needed the WRITE permission on the URI and setting up the selector intent. Thanks! – Kevin Aug 03 '20 at 18:03
  • 3
    Instead of checking package manager manually, you can also use the newer chooser, which also handles the state when user has no email apps. It will also show only email apps. `startActivity(Intent.createChooser(emailIntent, null));` – Pavel Haluza Aug 11 '20 at 16:59
  • This is the best Answer by far – dicarlomagnus Oct 17 '20 at 04:18
  • Any idea why the same logic doesn't work for SMS messages? – thepurpleowl Mar 29 '21 at 11:45
  • Yes! Intent.ACTION_SENDTO does not take Intent.EXTRA_STREAM. The mentioning of this helped me a lot. I wish I read your answer more carefully. Found out this was the issue by trial and error myself. Didn't realize it was in your answer all alone! lol – Haomin Jun 29 '21 at 18:49
  • `Intent#resolveActivity` is unreliable. On Google Pixel 4a it returns null but activity can be started regardless. Please use try-catch approach instead. See my solution: https://stackoverflow.com/a/61391007/1329901 – Egis Feb 11 '22 at 09:29
  • Using `Intent.createChooser(emailIntent)` additionally, made it work for me with attachements. – J. Hegg Apr 12 '22 at 08:34
  • You should receive a medal for this! Thank you! – dimsuz Oct 18 '22 at 16:59
28

I'm not taking credit for this answer but I believe it gives the best answer for this post.

It's a common misconception to use text/plain or text/html. This will trigger any application that can handle plain or HTML text files without any context, including Google Drive, Dropbox, Evernote and Skype.

Instead use a ACTION_SENDTO, providing the mailto: Uri

intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));

You can then proceed using the chooser as suggested through the other answers.

Answered by @PaulLammertsma here Android email chooser

Community
  • 1
  • 1
Etienne Lawlor
  • 6,817
  • 18
  • 77
  • 89
26
Intent email = new Intent(android.content.Intent.ACTION_SEND);  
email.setType("application/octet-stream");    

EDIT:
You could try setting the type to "message/rfc822" as well.

try this...

OhhhThatVarun
  • 3,981
  • 2
  • 26
  • 49
N-JOY
  • 10,344
  • 7
  • 51
  • 69
19

@Ganapathy:try this code for display gmail

Intent gmail = new Intent(Intent.ACTION_VIEW);
                gmail.setClassName("com.google.android.gm","com.google.android.gm.ComposeActivityGmail");
                gmail.putExtra(Intent.EXTRA_EMAIL, new String[] { "jckdsilva@gmail.com" });
                gmail.setData(Uri.parse("jckdsilva@gmail.com"));
                gmail.putExtra(Intent.EXTRA_SUBJECT, "enter something");
                gmail.setType("plain/text");
                gmail.putExtra(Intent.EXTRA_TEXT, "hi android jack!");
                startActivity(gmail);
Jack Dsilva
  • 1,504
  • 3
  • 24
  • 44
  • 16
    Be aware, this will only work if the device has Gmail installed. On non-Google devices (like, say, the Kindle Fire, which has its own e-mail client) it will fail. – Russell Stewart Sep 11 '12 at 18:47
  • How can you filter out all applications expect for email and gmail without creating a chooser? – Etienne Lawlor Mar 09 '14 at 23:11
15

This will help you.

On your button click : 

Intent email = new Intent(Intent.ACTION_SEND);
email.putExtra(Intent.EXTRA_EMAIL, new String[]{"youremail@yahoo.com"});          
email.putExtra(Intent.EXTRA_SUBJECT, "subject");
email.putExtra(Intent.EXTRA_TEXT, "message");
email.setType("message/rfc822");
startActivity(Intent.createChooser(email, "Choose an Email client :"));
Jignesh Mayani
  • 6,937
  • 1
  • 20
  • 36
8

Using message/rfc822 type as pointed here: ACTION_SEND force sending with email solves the issue.

Community
  • 1
  • 1
Gawcio
  • 1,125
  • 1
  • 9
  • 17
7

I had a similar problem with my app. I recently found this link form the official android developers site that really helps! Common Intents: Email

TL;DR:

Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("mailto:"));

Now, you will only be shown email clients!

You can add a Subject and Body by doing this:

intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
intent.putExtra(Intent.EXTRA_TEXT, "Body" );
A P
  • 2,131
  • 2
  • 24
  • 36
5

I notice, that this is an pretty old question but it is the first result when searching for a "Send mail" solution and all answers have a common problem:

Using Intent.ACTION_SEND and intent.setType("message/rfc822") will result in a chooser that not only shows mail apps but all apps that can handle any MIME type support by message/rfc822, e.g. .mhtml, .mht, .mime. Beside mail apps this could be Google Drive, Dropbox, Evernote, etc.

The only solution I found to limit the chooser to mail apps only is to use Intent.ACTION_SENDTO instead:

Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto","address@example.com", null));
intent.putExtra(Intent.EXTRA_SUBJECT, "My Mail");
intent.putExtra(Intent.EXTRA_TEXT   , "My Message");

try {
    startActivity(Intent.createChooser(i, "Send mail..."));
} catch (android.content.ActivityNotFoundException ex) {
    Toast.makeText(MainActivity.this, "There are no email clients installed.", Toast.LENGTH_SHORT).show();
}
Andrei Herford
  • 17,570
  • 19
  • 91
  • 225
4

Thanks to the Open source developer, cketti for sharing this concise and neat solution. It's the only method that worked for me.

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
2

First solution: try to be more specific in your Intent parameters. Add a message recipient for instance

emailIntent .putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {"user@example.com"});

Second solution: use the package manager to find all applications capable of sending a message and select the only those you want to use.

Jcs
  • 13,279
  • 5
  • 53
  • 70
2

Shout-out to ARLabs for posting the best solution on how to send an email on android. I just made a little update - an option to add multiple email attachements.

fun sendEmail(context: Context, recipients: List<String>?, subject: String?, body: String?, attachments: List<Uri>?) {
    val emailIntent = Intent(Intent.ACTION_SEND_MULTIPLE)
    emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    emailIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
    emailIntent.selector = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"))

    recipients?.let {
        val recipientsArray = arrayOfNulls<String>(recipients.size)
        ArrayList(recipients).toArray(recipientsArray)
        emailIntent.putExtra(Intent.EXTRA_EMAIL, recipientsArray)
    }
    subject?.let {
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject)
    }
    body?.let {
        emailIntent.putExtra(Intent.EXTRA_TEXT, body)
    }
    if (attachments?.isNotEmpty() == true) {
        emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, ArrayList(attachments))
    }

    try {
        context.startActivity(emailIntent)
    } catch (e: ActivityNotFoundException) {
        // TODO handle "no app to handle action" error
    }
}
Egis
  • 5,081
  • 5
  • 39
  • 61
1

This is a combination of Jack Dsilva and Jignesh Mayani solutions:

    try
    {
        Intent gmailIntent = new Intent(Intent.ACTION_SEND);
        gmailIntent.setType("text/html");

        final PackageManager pm = _activity.getPackageManager();
        final List<ResolveInfo> matches = pm.queryIntentActivities(gmailIntent, 0);
        String gmailActivityClass = null;

        for (final ResolveInfo info : matches)
        {
            if (info.activityInfo.packageName.equals("com.google.android.gm"))
            {
                gmailActivityClass = info.activityInfo.name;

                if (gmailActivityClass != null && !gmailActivityClass.isEmpty())
                {
                    break;
                }
            }
        }

        gmailIntent.setClassName("com.google.android.gm", gmailActivityClass);
        gmailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { "yourmail@gmail.com" });
        gmailIntent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
        gmailIntent.putExtra(Intent.EXTRA_CC, "cc@gmail.com"); // if necessary
        gmailIntent.putExtra(Intent.EXTRA_TEXT, "Email message");
        gmailIntent.setData(Uri.parse("yourmail@gmail.com"));
        this._activity.startActivity(gmailIntent);
    }

    catch (Exception e)
    {
        Intent i = new Intent(Intent.ACTION_SEND);
        i.putExtra(Intent.EXTRA_EMAIL, new String[] { "yourmail@gmail.com" });
        i.putExtra(Intent.EXTRA_SUBJECT, "Subject");
        i.putExtra(Intent.EXTRA_CC, "cc@gmail.com"); // if necessary
        i.putExtra(Intent.EXTRA_TEXT, "Email message");
        i.setType("plain/text");
        this._activity.startActivity(i);
    }

So, at first it will try to open gmail app and in case a user doesn't have it then the second approach will be implemented.

Ayaz Alifov
  • 8,334
  • 4
  • 61
  • 56
0

Best code to restrict it to only send an email. set this type to only send an email. i.setType("message/rfc822");

        Intent i = new Intent(Intent.ACTION_SEND);
        i.setType("message/rfc822");
        i.putExtra(Intent.EXTRA_EMAIL  , new String[]{"skapis1@outlook.com"});
        i.putExtra(Intent.EXTRA_SUBJECT, "subject of email");
        i.putExtra(Intent.EXTRA_TEXT   , "body of email");
        try {
            startActivity(Intent.createChooser(i, "Send mail..."));
        } catch (android.content.ActivityNotFoundException ex) {
            Toast.makeText(Firstclass.this, "There are no email clients installed.", Toast.LENGTH_SHORT).show();
        }
Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300
0

This saved my day. It sends composed text message directly to gmail app:

Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(
                        "mailto","togmail.com", null));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Report message");
emailIntent.putExtra(Intent.EXTRA_TEXT, edt_msg.getText().toString());
startActivity(Intent.createChooser(emailIntent, "Send email..."));
Pang
  • 9,564
  • 146
  • 81
  • 122
Abhilasha
  • 51
  • 6
0

This will open only the Email app installed in your android phone.

        Intent intent = new Intent(Intent.ACTION_SENDTO);
        intent.setData(Uri.parse("mailto:"));
        intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"example@gmail.com"});
        intent.putExtra(Intent.EXTRA_SUBJECT, "email subject");
        intent.putExtra(Intent.EXTRA_TEXT, "message body");

        try {
            startActivity(Intent.createChooser(intent, "send mail"));
        } catch (ActivityNotFoundException ex) {
            Toast.makeText(this, "No mail app found!!!", Toast.LENGTH_SHORT);
        } catch (Exception ex) {
            Toast.makeText(this, "Unexpected Error!!!", Toast.LENGTH_SHORT);
        }
0
public class MainActivity extends AppCompatActivity {

  private EditText edt_email;
  private Button btn_send;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    edt_email = (EditText) findViewById(R.id.edt_email);
    btn_send = (Button) findViewById(R.id.btn_send);

    btn_send.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {

        Intent intent = new Intent(Intent.ACTION_SEND );
        intent.putExtra(Intent.EXTRA_EMAIL , new String[]{"sanaebadi97@gmail.com"});
        intent.putExtra(Intent.EXTRA_SUBJECT , "subject");
        intent.putExtra(Intent.EXTRA_TEXT , "My Email Content");
        intent.setType("message/rfc822");
        startActivity(Intent.createChooser(intent , "Choose Your Account : "));
      }
    });
  }
}
Meysam Keshvari
  • 1,141
  • 12
  • 14
0

try with ACTION_VIEW not ACTION_SENDTO , ACTION_VIEW will makes system calls only to Email Apps

Intent emailIntent = new Intent(Intent.ACTION_VIEW);
Raouf
  • 21
  • 1
  • 4