Slack users.lookupByEmail: Get a User ID From an Email, Tested
users.lookupByEmail turns an email address into a Slack user ID. It needs the users:read.email scope. We ran it with the right and wrong emails, upper case, spaces and a token without the scope, in curl and Python, and list every response.
On this page
To get a Slack user ID from an email address, call users.lookupByEmail with email= and a token that has the users:read.email scope. Slack returns the full user object, and user.id is the ID (U...) you use for mentions and DMs. If no member of the workspace has that address, the answer is users_not_found. We ran each case below on 1 October 2026, with a test app in our own workspace. The lookup still worked after we hid email addresses from profiles, as our hide your email on Slack test shows.
Call users.lookupByEmail
Add users:read.email to the bot scopes (our app also had users:read), reinstall, and call:
curl -s https://slack.com/api/users.lookupByEmail \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-d email=you@example.com
The top-level fields of our response, with our own address:
{"id": "U0B7L4YK420", "team_id": "T0B7JBCDKC1", "name": "sieun", "deleted": false, "real_name": "sieun", "tz": "Asia/Seoul", "is_admin": true, "is_owner": true, "is_bot": false, "is_email_confirmed": true}
That object sits under user in the response, next to "ok": true. It also has a profile with email, display_name, status_text and the avatar URLs. A GET request with ?email= worked too.
What different emails returned
What we sent as email | Result |
|---|---|
| The member's address | ok: true, U0B7L4YK420 |
| The same address in upper case | ok: true, U0B7L4YK420 |
| The address with a space before and after | users_not_found |
The address with +test added before the @ | users_not_found |
| An address no member has | users_not_found |
not-an-email | users_not_found |
| An empty string | users_not_found |
No email field at all | invalid_arguments |
Case does not matter, spaces do. Trim the input before the call, because a spreadsheet cell with a trailing space looks like an unknown person. A plus alias is a different address to Slack, even if the mail server delivers it to the same inbox. A missing field gives a clearer error than an empty one:
{"ok": false, "error": "invalid_arguments", "response_metadata": {"messages": ["[ERROR] missing required field: email"]}}
Slack checks the email against the address on the member's account, the one shown under Contact information on their profile. A person who signed up with a personal address and uses a work address in your company directory is users_not_found.
Never appear "away" on Slack again
Cloud-based. No downloads. Works 24/7 even when your laptop is off.
The scope error, and which token sees emails
Our user token had users:read but not users:read.email. The lookup with it returned:
{"ok": false, "error": "missing_scope", "needed": "users:read.email", "provided": "identify,channels:history,search:read,users:read,chat:write,search:read.public"}
Add the scope from needed to the same token type you call with, then reinstall; the steps are in missing_scope. The scope also changes other methods. users.info for the same person, with the user token that had only users:read, returned a profile with no email field and no error. With the bot token that had users:read.email, the field was there. Code that reads profile["email"] gets a KeyError with the first token and works with the second.
Look up a user by email in Python
We ran this with slack_sdk:
import os
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
def user_id_for(email):
try:
return client.users_lookupByEmail(email=email)["user"]["id"]
except SlackApiError as e:
if e.response["error"] == "users_not_found":
return None
raise
print(user_id_for(os.environ["OWNER_EMAIL"]))
print(user_id_for("nobody-w1test@example.com"))
U0B7L4YK420
None
users_not_found is a normal answer, so the function returns None for it and raises for everything else, such as missing_scope or invalid_auth. With the ID you can mention the person as <@U0B7L4YK420> or open a DM; the other ways to find an ID, including by hand from a profile, are in Slack member ID. To post the result to a channel, see send a Slack message from Python.
FAQ
Can I look up many emails at once?
There is no batch method. One call takes one address. For a large list, users.list with users:read.email returns every member with their email, 200 per page, and you can match locally.
Stop Jiggling Your Mouse.
Join hundreds of remote workers who never worry about their Slack status. Set it up once, stay green forever.
Related Articles
How to See All Your DMs in Slack, Including the Hidden Ones
The DMs tab lists your direct messages with people. App DMs, Slackbot and DMs with deleted accounts sit elsewhere. We compared the tab with the full list the Slack API returned.
Slack Images Not Showing? 5 Causes We Reproduced
We uploaded images to a Slack test channel and then switched each image setting off, ran /collapse, and posted from a bot that was not in the channel. Five causes, each reproduced.
How to Message Yourself on Slack (and What It Notifies)
Your own name under Direct messages opens a private DM with yourself. We sent it a note, a file, a scheduled message and a reminder, and checked which ones raised a badge.