How to get the Android device's primary e-mail address
Asked Answered
D

13

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.

Dunlop answered 21/1, 2010 at 21:14 Comment(4)
Are you talking about retrieving a contacts email address?Engadine
No, the device's primary e-mail address.Pskov
There are one or more e-mail addresses associated with an Android device right? That's what I'd want.Pskov
@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 #10607476Scabious
L
751

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" />
Linsk answered 1/2, 2010 at 9:34 Comment(20)
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.Semiliterate
any better way that would you suggest to get the primary gmail id.Semiliterate
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?Outlawry
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.Photoflood
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?Groan
@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. @Groan — I don't think so, but com.google is fairly stable.Linsk
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!Awry
@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.)Awry
"Fortunately, for certain account types (including com.google), the account names are email addresses" - is this an official statement or just by your testing ?Enravish
@Enravish 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.Linsk
@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.Berton
@RomanNurik Looking in ContactsContract.Contacts.Data I can see no constant for IS_PRIMARY. Am I looking in a wrong class?Inaccuracy
I agree with @Awry 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.Regulus
Method B is not working for me in Android 4.4 copying all the example code. cursor.isAfterLast() always returns true. Any idea?Banshee
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.Surfacetoair
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.Emmie
Since M, we need to ask runtime permissions.Deianira
@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?Thermoelectric
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.Anthracite
@RomanNurik Does the Method B work for android version from and after marshmellow?Bisset
H
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.

Hasidism answered 18/10, 2013 at 8:14 Comment(2)
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 PlayThrill
@Thrill Does this work for android versions after/from marshmellow?Bisset
D
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);
    }
}
Decencies answered 12/11, 2014 at 13:33 Comment(4)
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.Thermoelectric
Using AccountManager.newChooseAccountIntent() do the same job and does not require the play-services library.Stripy
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?Bisset
this is the best answer, just got a real account, with user interact.Brezin
C
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;
}
Continent answered 13/4, 2016 at 12:5 Comment(5)
Nice and easy method Thanks :)Paroicous
Notice this requires android.permission.GET_ACCOUNTS, which defined as 'dangerous' permission (requires runtime request) : developer.android.com/reference/android/…Immodest
@Immodest 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 :)Undefined
@Undefined I didn't ... it's not possible as far as I know.Immodest
manager.getAccountsByType("com.google"); does not work with later versions of Android.Disrelish
B
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()

Bower answered 17/7, 2018 at 6:24 Comment(1)
I can confirm I was able to use this , thanks for the only working answer I've foundAnthracite
L
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;
}
Legislatorial answered 22/7, 2016 at 10:30 Comment(0)
K
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:

Kisser answered 29/1, 2010 at 20:57 Comment(0)
S
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());
Salema answered 31/3, 2018 at 22:2 Comment(2)
This seems to only return accounts associated with the current app - so I get "none" in testingAnthracite
manager.getAccountsByType("com.google") does not work in later versions of Android. And what is App.getInstance() from?Disrelish
H
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;
}
Heronry answered 17/12, 2019 at 11:29 Comment(0)
N
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

Neogothic answered 18/3, 2020 at 6:51 Comment(0)
A
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

Asafoetida answered 24/3, 2021 at 9:56 Comment(0)
F
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);


            }
        }
    });
Fuliginous answered 12/7, 2017 at 11:52 Comment(3)
<uses-permission android:name="android.permission.GET_ACCOUNTS" />Fuliginous
Get accounts answers haven't worked for me (return 0 accounts) - and I can confirm that calling the code in a button callback made no difference.Anthracite
This Code is working but recently i have time issue so please check our sideFuliginous
S
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);
        }
    }
}
Suppliant answered 26/3, 2018 at 20:58 Comment(1)
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.Anthracite

© 2022 - 2024 — McMap. All rights reserved.