420

How do you get the Android's primary e-mail address (or a list of e-mail addresses)?

It's my understanding that on OS 2.0+ there's support for multiple e-mail addresses, but below 2.0 you can only have one e-mail address per device.

Apurva
  • 7,871
  • 7
  • 40
  • 59
Brandon O'Rourke
  • 24,165
  • 16
  • 57
  • 58
  • Are you talking about retrieving a contacts email address? – Austyn Mahoney Jan 21 '10 at 23:40
  • 1
    No, the device's primary e-mail address. – Brandon O'Rourke Jan 22 '10 at 16:34
  • There are one or more e-mail addresses associated with an Android device right? That's what I'd want. – Brandon O'Rourke Jan 29 '10 at 17:38
  • 2
    @BrandonO'Rourke Do you mean "the device's primary e-mail Address" as the one associated with the Android Market? Because there is a difference between the gmail id associated with the Android Market and other emails. Have a look at this question http://stackoverflow.com/questions/10606976/how-to-find-gmail-account-associated-with-android-market#comment13831559_10606976 – Gaurav Agarwal May 19 '12 at 09:28

13 Answers13

750

There are several ways to do this, shown below.

As a friendly warning, be careful and up-front to the user when dealing with account, profile, and contact data. If you misuse a user's email address or other personal information, bad things can happen.

Method A: Use AccountManager (API level 5+)

You can use AccountManager.getAccounts or AccountManager.getAccountsByType to get a list of all account names on the device. Fortunately, for certain account types (including com.google), the account names are email addresses. Example snippet below.

Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
Account[] accounts = AccountManager.get(context).getAccounts();
for (Account account : accounts) {
    if (emailPattern.matcher(account.name).matches()) {
        String possibleEmail = account.name;
        ...
    }
}

Note that this requires the GET_ACCOUNTS permission:

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

More on using AccountManager can be found at the Contact Manager sample code in the SDK.

Method B: Use ContactsContract.Profile (API level 14+)

As of Android 4.0 (Ice Cream Sandwich), you can get the user's email addresses by accessing their profile. Accessing the user profile is a bit heavyweight as it requires two permissions (more on that below), but email addresses are fairly sensitive pieces of data, so this is the price of admission.

Below is a full example that uses a CursorLoader to retrieve profile data rows containing email addresses.

public class ExampleActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getLoaderManager().initLoader(0, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle arguments) {
        return new CursorLoader(this,
                // Retrieve data rows for the device user's 'profile' contact.
                Uri.withAppendedPath(
                        ContactsContract.Profile.CONTENT_URI,
                        ContactsContract.Contacts.Data.CONTENT_DIRECTORY),
                ProfileQuery.PROJECTION,

                // Select only email addresses.
                ContactsContract.Contacts.Data.MIMETYPE + " = ?",
                new String[]{ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE},

                // Show primary email addresses first. Note that there won't be
                // a primary email address if the user hasn't specified one.
                ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        List<String> emails = new ArrayList<String>();
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            emails.add(cursor.getString(ProfileQuery.ADDRESS));
            // Potentially filter on ProfileQuery.IS_PRIMARY
            cursor.moveToNext();
        }

        ...
    }

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
    }

    private interface ProfileQuery {
        String[] PROJECTION = {
                ContactsContract.CommonDataKinds.Email.ADDRESS,
                ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
        };

        int ADDRESS = 0;
        int IS_PRIMARY = 1;
    }
}

This requires both the READ_PROFILE and READ_CONTACTS permissions:

<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Roman Nurik
  • 29,665
  • 7
  • 84
  • 82
  • 4
    i have similar question using your code i am able to get the all gmail id's associated with my phone but i want the primary one. I found one solution like as we add more mail id's to synchronize with phone it comes into a stack if i am getting the 0th position com.google id's, i am getting the primary one because it enter first and acquire the 0th position in a stack. Here's my some code Account[] accounts=AccountManager.get(this).getAccountsByType("com.google"); String myEmailid=accounts[0].toString(); Log.d("My email id that i want", myEmailid); i know its not the correct way. – PiyushMishra May 18 '11 at 09:15
  • any better way that would you suggest to get the primary gmail id. – PiyushMishra May 18 '11 at 09:17
  • 1
    GET_ACCOUNTS is a really heavy duty permission; it will let my app access Twitter and Facebook accounts, in addition to all email addresses. [Is there really no nicer way to get a user's email address?](http://stackoverflow.com/questions/6502017/getting-android-owners-email-address-nicely) – Dan Fabulich Jun 30 '11 at 04:37
  • 2
    This doesn't work at all on the Nook. The account.name returns "device" or "user" and not an email address so a regex is useless. – Christopher Perry Nov 22 '11 at 01:29
  • does google provide a static constant somewhere for the "com.google" type string? or do I have to re-declare it in all of my apps? – gnomed Mar 21 '12 at 22:58
  • 1
    @ChristopherPerry — there's no guarantee that the `AccountManager` method works. It's basically a hack. @DanFabulich — the user's email addresses are sensitive data, so it's rightfully behind permissions. @gnomed — I don't think so, but `com.google` is fairly stable. – Roman Nurik May 06 '12 at 22:09
  • 61
    The profile method is badly flawed (in my opinion). An app that wants/needs my e-mail is not a big deal compared to an app that wants to read all my contacts, but you've made it so that they both require the same permissions. So as a user, I can't tell the difference between an app that is going to read my e-mail, and an app that is going to read my 500+ contacts. This is a very real, practical problem as the number of apps that abuse your contacts is growing! – Tom May 17 '12 at 16:35
  • @DanFabulich, you mention that GET_ACCOUNTS is a heavy duty permission but at least, in granting that permission to an app, a user is just exposing their own information. The alternative method requires READ_CONTACTS and I would argue that their is nothing more heavy duty then giving away the personal information of everyone you know. (For a high profile example, take a look at Hookt messenger.) – Tom May 17 '12 at 16:41
  • "Fortunately, for certain account types (including com.google), the account names are email addresses" - is this an official statement or just by your testing ? – Muzikant May 20 '12 at 08:30
  • 3
    @Muzikant It's by no means an official statement, but it's something that's fairly unlikely to change. Having said that, the "correct" way of accessing a user's email addresses is Method B. That is more "official" and the fact that it's behind some heavyweight permissions should indicate the sensitivity with which you should approach such data. – Roman Nurik Jun 09 '12 at 16:42
  • 1
    @RomanNurik Reto and Ian are constantly mentioning using the fact that the device already has the user's email address/name/google account (almost always) when dealing with account creation. If I am conscience of the sensitivity of this information, than using your methods (degrading to A for compatibility) is correct design for such an app? Also, I'm assuming the person's name is similarly retrieved, would you know about that? Also, thanks for the answer. – Dandre Allison Nov 10 '12 at 16:48
  • @RomanNurik Looking in [ContactsContract.Contacts.Data](http://developer.android.com/reference/android/provider/ContactsContract.Contacts.Data.html) I can see no constant for IS_PRIMARY. Am I looking in a wrong class? – gunar Sep 13 '13 at 14:21
  • 15
    I agree with @Tom on this. Asking permission for the data of the all contacts on the phone for just the First and Last name of the user is ridiculous. – tasomaniac Oct 29 '13 at 13:32
  • 4
    Method B is not working for me in Android 4.4 copying all the example code. `cursor.isAfterLast()` always returns true. Any idea? – cprcrack Feb 04 '14 at 17:36
  • If 'cursor.isAfterLast()' returns true it means the user hasn't added a profile via the People app. It needs to be added manually by the user to work. – marmor Aug 03 '14 at 11:34
  • How to find which account is currently in use by Google Play(I consider that the primary email)? Using method 1 gives all google accounts on the device but no clue on which one is in use for billing. – A.J. Jan 04 '15 at 14:19
  • Since M, we need to ask runtime permissions. – Romain Jan 29 '16 at 11:55
  • 1
    @RomanNurik About method B, it doesn't work (tested on Nexus 5x device): if the user hasn't put/modified anything in its profile contact ("ME"), it creates an empty list. That's even though there is an account of the user, which is used for Gmail, downloading apps, etc... Why do you think that the AccountManager method isn't a good solution? – android developer May 15 '16 at 08:54
  • Method A seems to only return accounts associated with the current app - so I get "none" in testing. Method B seems problematic. Wirlings answer worked much better for me. – csga5000 Jul 18 '18 at 15:49
  • @RomanNurik Does the Method B work for android version from and after marshmellow? – Eswar Oct 12 '18 at 06:55
55

This could be useful to others:

Using AccountPicker to get user's email address without any global permissions, and allowing the user to be aware and authorize or cancel the process.

Community
  • 1
  • 1
Jorge Cevallos
  • 3,667
  • 3
  • 25
  • 37
  • 1
    This is a very helpful answer, I think this should be the preferred option as **Primary Email** usually means the Google Account, which in turn you will have in conjunction with **Google Play** – Alex.F Oct 23 '14 at 10:11
  • @Alex.F Does this work for android versions after/from marshmellow? – Eswar Oct 12 '18 at 06:56
28

I would use Android's AccountPicker, introduced in ICS.

Intent googlePicker = AccountPicker.newChooseAccountIntent(null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null);
startActivityForResult(googlePicker, REQUEST_CODE);

And then wait for the result:

protected void onActivityResult(final int requestCode, final int resultCode,
                                final Intent data) {
    if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
        String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
    }
}
SeBsZ
  • 485
  • 4
  • 8
  • 2
    Note that it requires you to use play-services, and that it will show a dialog in some cases, that the user will need to choose the account. – android developer May 15 '16 at 07:48
  • 1
    Using AccountManager.newChooseAccountIntent() do the same job and does not require the play-services library. – Greelings Aug 02 '18 at 14:27
  • Does this throw a pop up to the user for account authentication in the context of the latest android version? If yes how do I bypass that for a device having only one account? – Eswar Oct 12 '18 at 09:32
  • this is the best answer, just got a real account, with user interact. – Noor Hossain Dec 18 '20 at 23:22
14
public String getUsername() {
    AccountManager manager = AccountManager.get(this);
    Account[] accounts = manager.getAccountsByType("com.google");
    List<String> possibleEmails = new LinkedList<String>();

    for (Account account : accounts) {
        // TODO: Check possibleEmail against an email regex or treat
        // account.name as an email address only for certain account.type values.
        possibleEmails.add(account.name);
    }

    if (!possibleEmails.isEmpty() && possibleEmails.get(0) != null) {
        String email = possibleEmails.get(0);
        String[] parts = email.split("@");

        if (parts.length > 1)
            return parts[0];
    }
    return null;
}
Afzaal Iftikhar
  • 233
  • 2
  • 5
  • Nice and easy method Thanks :) – Talha Q Dec 09 '16 at 05:53
  • 2
    Notice this requires `android.permission.GET_ACCOUNTS`, which defined as 'dangerous' permission (requires runtime request) : https://developer.android.com/reference/android/Manifest.permission.html#GET_ACCOUNTS – SagiLow Apr 17 '17 at 09:13
  • @SagiLow How did you handle this? I don't want to ask user, for an another permission, just to make him lazy to enter his email address :) – codebased May 27 '17 at 01:25
  • 1
    @codebased I didn't ... it's not possible as far as I know. – SagiLow May 27 '17 at 08:42
  • 3
    manager.getAccountsByType("com.google"); does not work with later versions of Android. – powder366 Dec 31 '18 at 17:24
8

There is an Android api that allows the user to select their email address without the need for a permission. Take a look at: https://developers.google.com/identity/smartlock-passwords/android/retrieve-hints

HintRequest hintRequest = new HintRequest.Builder()
        .setHintPickerConfig(new CredentialPickerConfig.Builder()
                .setShowCancelButton(true)
                .build())
        .setEmailAddressIdentifierSupported(true)
        .setAccountTypes(IdentityProviders.GOOGLE)
        .build();

PendingIntent intent = mCredentialsClient.getHintPickerIntent(hintRequest);
try {
    startIntentSenderForResult(intent.getIntentSender(), RC_HINT, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
    Log.e(TAG, "Could not start hint picker Intent", e);
}

This will show a picker where the user can select an emailaddress. The result will be delivered in onActivityResult()

Wirling
  • 4,810
  • 3
  • 48
  • 78
7

Sadly accepted answer isn't working.

I'm late, but here's the solution for internal Android Email application unless the content uri is changed by provider:

Uri EMAIL_ACCOUNTS_DATABASE_CONTENT_URI = 
              Uri.parse("content://com.android.email.provider/account");

public ArrayList<String> GET_EMAIL_ADDRESSES ()
{
    ArrayList<String> names = new ArrayList<String>();
    ContentResolver cr      = m_context.getContentResolver();
    Cursor cursor           = cr.query(EMAIL_ACCOUNTS_DATABASE_CONTENT_URI ,null, 
                             null, null, null);

    if (cursor == null) {
        Log.e("TEST", "Cannot access email accounts database");
        return null;
    }

    if (cursor.getCount() <= 0) {
        Log.e("TEST", "No accounts");
        return null;
    }

    while (cursor.moveToNext()) {
        names.add(cursor.getString(cursor.getColumnIndex("emailAddress")));
        Log.i("TEST", cursor.getString(cursor.getColumnIndex("emailAddress")));
    }
    return names;
}
Burak Day
  • 907
  • 14
  • 28
6

This is quite the tricky thing to do in Android and I haven't done it yet. But maybe these links may help you:

Hartmut Pfitzinger
  • 2,304
  • 3
  • 28
  • 48
AGrunewald
  • 1,735
  • 3
  • 16
  • 25
3

Use this method:

 public String getUserEmail() {
    AccountManager manager = AccountManager.get(App.getInstance());
    Account[] accounts = manager.getAccountsByType("com.google");
    List<String> possibleEmails = new LinkedList<>();
    for (Account account : accounts) {
        possibleEmails.add(account.name);
    }
    if (!possibleEmails.isEmpty() && possibleEmails.get(0) != null) {
        return possibleEmails.get(0);
    }
    return "";
}

Note that this requires the GET_ACCOUNTS permission:

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

Then:

editTextEmailAddress.setText(getUserEmail());
Iman Marashi
  • 5,593
  • 38
  • 51
  • This seems to only return accounts associated with the current app - so I get "none" in testing – csga5000 Jul 18 '18 at 15:36
  • 1
    manager.getAccountsByType("com.google") does not work in later versions of Android. And what is App.getInstance() from? – powder366 Dec 31 '18 at 17:20
1

Add this single line in manifest (for permission)

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

Then paste this code in your activity

private ArrayList<String> getPrimaryMailId() {
    ArrayList<String> accountsList = new ArrayList<String>();
    try {
        Account[] accounts = AccountManager.get(this).getAccountsByType("com.google");
        for (Account account : accounts) {
            accountsList.add(account.name);
            Log.e("GetPrimaryMailId ", account.name);
        }
    } catch (Exception e) {
        Log.e("GetPrimaryMailId", " Exception : " + e);
    }
    return accountsList;
}
Agilanbu
  • 2,747
  • 2
  • 28
  • 33
1

The suggested answers won't work anymore as there is a new restriction imposed from android 8 onwards.

more info here: https://developer.android.com/about/versions/oreo/android-8.0-changes.html#aaad

hushed_voice
  • 3,161
  • 3
  • 34
  • 66
1

For Android 8 and above -

Step 1 - Add the following code in AndroidManifest.xml -

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

Step 2 - Add the following code in your activity asking for permissions at runtime.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if ((ActivityCompat.checkSelfPermission(this, Manifest.permission.GET_ACCOUNTS) == PackageManager.PERMISSION_GRANTED) && (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED)) {
                getGoogleAccounts();
            }

            else {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.GET_ACCOUNTS, Manifest.permission.READ_CONTACTS}, 1);
                //return false;
            }
        }

Step 3 - Add code for onRequestPermissionsResult -

 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){

            getGoogleAccounts();
        }
    }

Step 4 - Finally add code to retrieve account using AccountManager

private void getGoogleAccounts(){

   AccountManager am = AccountManager.get(this); // "this" references the current Context
    Account[] accounts = am.getAccountsByType("com.google");

    for (Account acc : accounts){
        System.out.println("http accounts " + acc);
    }
}

Please refer to following link for changes in android 8 - https://developer.android.com/about/versions/oreo/android-8.0-changes#aaad

0

Working In MarshMallow Operating System

    btn_click=(Button) findViewById(R.id.btn_click);

    btn_click.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0)
        {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
            {
                int permissionCheck = ContextCompat.checkSelfPermission(PermissionActivity.this,
                        android.Manifest.permission.CAMERA);
                if (permissionCheck == PackageManager.PERMISSION_GRANTED)
                {
                    //showing dialog to select image
                    String possibleEmail=null;

                     Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
                     Account[] accounts = AccountManager.get(PermissionActivity.this).getAccounts();
                     for (Account account : accounts) {
                         if (emailPattern.matcher(account.name).matches()) {
                             possibleEmail = account.name;
                             Log.e("keshav","possibleEmail"+possibleEmail);
                         }
                     }

                    Log.e("keshav","possibleEmail gjhh->"+possibleEmail);
                    Log.e("permission", "granted Marshmallow O/S");

                } else {                        ActivityCompat.requestPermissions(PermissionActivity.this,
                            new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE,
                                    android.Manifest.permission.READ_PHONE_STATE,
                                    Manifest.permission.GET_ACCOUNTS,
                                    android.Manifest.permission.CAMERA}, 1);
                }
            } else {
// Lower then Marshmallow

                    String possibleEmail=null;

                     Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
                     Account[] accounts = AccountManager.get(PermissionActivity.this).getAccounts();
                     for (Account account : accounts) {
                         if (emailPattern.matcher(account.name).matches()) {
                             possibleEmail = account.name;
                             Log.e("keshav","possibleEmail"+possibleEmail);
                     }

                    Log.e("keshav","possibleEmail gjhh->"+possibleEmail);


            }
        }
    });
Amrut Bidri
  • 6,276
  • 6
  • 38
  • 80
Keshav Gera
  • 10,807
  • 1
  • 75
  • 53
0

Android locked down GET_ACCOUNTS recently so some of the answers did not work for me. I got this working on Android 7.0 with the caveat that your users have to endure a permission dialog.

AndroidManifest.xml

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

MainActivity.java

package com.example.patrick.app2;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.accounts.AccountManager;
import android.accounts.Account;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.*;

public class MainActivity extends AppCompatActivity {

    final static int requestcode = 4; //arbitrary constant less than 2^16

    private static String getEmailId(Context context) {
        AccountManager accountManager = AccountManager.get(context);
        Account[] accounts = accountManager.getAccountsByType("com.google");
        Account account;
        if (accounts.length > 0) {
            account = accounts[0];
        } else {
            return "length is zero";
        }
        return account.name;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case requestcode:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    String emailAddr = getEmailId(getApplicationContext());
                    ShowMessage(emailAddr);

                } else {
                    ShowMessage("Permission Denied");
                }
        }
    }

    public void ShowMessage(String email)
    {
        AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create();
        alertDialog.setTitle("Alert");
        alertDialog.setMessage(email);
        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
        alertDialog.show();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Context context = getApplicationContext();

        if ( ContextCompat.checkSelfPermission( context, android.Manifest.permission.GET_ACCOUNTS )
                != PackageManager.PERMISSION_GRANTED )
        {
            ActivityCompat.requestPermissions( this, new String[]
                            {  android.Manifest.permission.GET_ACCOUNTS  },requestcode );
        }
        else
        {
            String possibleEmail = getEmailId(getApplicationContext());
            ShowMessage(possibleEmail);
        }
    }
}
patrick
  • 16,091
  • 29
  • 100
  • 164
  • This doesn't differ from other answers and it like those isn't working for me - seemingly because in newer versions of android this only returns accounts associated with the app and no longer requires the permission. – csga5000 Jul 18 '18 at 15:48