Gmail API scopes: request gmail.send, nothing more
Request https://www.googleapis.com/auth/gmail.send and nothing broader. Google classifies gmail.send as a sensitive scope, so the app needs OAuth verification — a verified domain, a hosted privacy policy, a demo video and a written justification per scope — but no third-party security audit. gmail.readonly, gmail.compose, gmail.modify and the full mail.google.com scope are restricted, and an app that can reach that data from a server must also pass a security assessment Google requires roughly once a year and does not pay for.
If your product sends mail and never needs to read it, this whole decision is one line in your OAuth config. Pick the wrong line and you have bought yourself a recurring third-party security assessment, a verification queue measured in weeks, and a bill nobody published in advance.
Which Gmail scope does a send-only app need?
https://www.googleapis.com/auth/gmail.send. That is the narrowest scope that authorises users.messages.send, and it is the only one of the send-capable scopes that Google classifies as sensitive rather than restricted.
You do not have to take a blog post’s word for which scopes authorise the send endpoint. The Gmail API publishes a machine-readable discovery document, and the answer is a single jq expression away:
$ curl -s 'https://gmail.googleapis.com/$discovery/rest?version=v1' \
| jq -r '.resources.users.resources.messages.methods.send.scopes[]'
https://mail.google.com/
https://www.googleapis.com/auth/gmail.addons.current.action.compose
https://www.googleapis.com/auth/gmail.compose
https://www.googleapis.com/auth/gmail.modify
https://www.googleapis.com/auth/gmail.sendFive entries. Worth noting that the human-readable reference page for users.messages.send lists four — it omits the add-ons scope — so the discovery document is the more complete answer. Of the five, one is non-sensitive but is described as applying when a user interacts with an add-on, three are restricted, and exactly one is a plain sensitive scope you can use from an ordinary web app: gmail.send.
The endpoint itself is POST https://gmail.googleapis.com/gmail/v1/users/{userId}/messages/send. Google’s sending guide describes the payload plainly: "Gmail messages are sent as base64URL encoded strings within the raw field of a messages resource", and the API "requires MIME email messages compliant with RFC 2822". gmail.send is enough to call it. It is not enough to list a thread, fetch a message, or read a label — which is the point.
What is the difference between a sensitive and a restricted scope?
Google puts OAuth scopes in three buckets. Non-sensitive scopes trigger no scope review at all — at most Google’s separate brand verification of the logo, display name and domain. Sensitive scopes need verification: a human at Google reads your justification and checks that your use of the scope, in Google’s words, "is not deceptive and in alignment with the appropriate use case". Restricted scopes need all of that plus an independent security assessment.
The trigger sentence on Google’s restricted scope verification page is worth reading literally, because the condition matters:
Every app that requests access to Google users’ restricted data and has the ability to access data from or through a third-party server must go through a security assessment from Google-empanelled security assessors.
Google, Restricted scope verification
A hosted SaaS with a backend is precisely the app that sentence describes. If you hold refresh tokens on a server and call Gmail from that server, requesting any restricted scope puts you in scope for the assessment. Google standardises it on the App Defense Alliance’s Cloud Application Security Assessment framework, which the Alliance describes as a "risk-based, multi-tier assessment approach to evaluate application risk based on user, scope, and other application specific items".
| Scope | Class | Google’s description | What it costs you |
|---|---|---|---|
| https://mail.google.com/ | Restricted | Read, compose, send, and permanently delete all your email from Gmail | Verification + security assessment |
| .../auth/gmail.modify | Restricted | Read, compose, and send emails from your Gmail account. This scope does not allow immediate, permanent deletion. | Verification + security assessment |
| .../auth/gmail.compose | Restricted | Manage drafts and send emails | Verification + security assessment |
| .../auth/gmail.readonly | Restricted | View your email messages and settings | Verification + security assessment (and it cannot send) |
| .../auth/gmail.send | Sensitive | Send email on your behalf | Verification only |
Note the fourth row. gmail.readonly is restricted and does not appear in the send endpoint’s scope list at all, so an app that asks for both readonly and send has paid the full restricted price and gained nothing on the sending side.
What does Google’s OAuth verification actually ask for?
Less than people fear, and it is the same list for sensitive and restricted scopes. Google’s verification pages ask for:
- Domain ownership. "Verify ownership of your project’s authorized domains within the Google Search Console."
- A homepage. "Your home page must be publicly accessible, and not just accessible to your site’s logged-in users."
- A privacy policy that "must be visible to users, hosted within the same domain as your application’s home page, and linked to on the OAuth consent screen", and that discloses how you access, use, store and share Google user data.
- A demo video. "Prepare a video that fully demonstrates how a user initiates and grants access to the requested scopes and shows, in detail, the usage of the granted sensitive and restricted scopes in the app."
- A justification per scope, including "an explanation for why a narrower scope isn’t sufficient".
- For restricted scopes only: a Letter of Assessment from a CASA assessor.
That last requirement in item five is the whole article in one sentence. A reviewer is going to ask you why gmail.send was not enough. If the honest answer is "it was", you are about to spend weeks explaining otherwise.
Timelines: Google’s pages do not agree with each other, so plan on the pessimistic figure. The sensitive scope verification page says the process "typically takes 3-5 business days to complete"; the OAuth verification FAQ puts sensitive scope verification at 10 business days and restricted scope verification at 6 weeks. The FAQ also says the estimates "are not guaranteed" and depend on how quickly you respond. The restricted scope page independently warns that verification "can potentially take several weeks to complete".
What does the CASA security assessment cost?
Google does not say, because Google is not the one charging. Two sentences from the verification FAQ set the shape of it: "Google does not charge the developer any fees for security assessment", and "The cost for such a service is agreed on between the developer and the assessor without any involvement from Google."
So there is no published price to quote, and figures circulating on forums and vendor blogs range over more than an order of magnitude. Some of that spread is real — tiers differ, and a small single-scope app is not a large platform — and some of it is people quoting each other. Treat every number you read, including the reassuring ones, as unverified until an authorised assessor has quoted you directly.
Can you skip verification by staying in Testing?
Only if you are not running a business. A project whose publishing status is Testing is "limited to up to 100 test users listed in the OAuth consent screen", and Google is explicit about what happens to those grants: "Authorizations by a test user will expire seven days from the time of consent. If your OAuth client requests an offline access type and receives a refresh token, that token will also expire."
A weekly reconsent prompt is not a product. Testing mode is for development, and the seven-day refresh token expiry is the mechanism that makes sure it stays that way.
What is the Microsoft 365 equivalent of this decision?
The same shape, different failure mode. Microsoft Graph’s sendMail action lists Mail.Send as the least privileged permission for all three access types, and — unusually — lists "Not available" under higher privileged permissions. There is no broader mail-sending permission to accidentally request. The choice is not which permission, but which kind.
POST https://graph.microsoft.com/v1.0/me/sendMail
Content-type: application/json
{
"message": {
"subject": "Meet for lunch?",
"body": { "contentType": "Text", "content": "The new cafeteria is open." },
"toRecipients": [ { "emailAddress": { "address": "frannis@contoso.com" } } ]
},
"saveToSentItems": "false"
}
HTTP/1.1 202 AcceptedDelegated Mail.Send acts on behalf of a signed-in user, and Microsoft is clear that "the application can’t access anything the signed-in user couldn’t access". A user can consent for their own data, although Microsoft also notes that "User consent availability also depends on your tenant’s app consent policies" — so a locked-down tenant can still route the grant to an admin.
Application permissions are a different animal. They work without a signed-in user, "Only admin can consent" to them, and the app "can access any data that the permission is associated with". Exchange Online spells out what that means for mail: the Application Mail.Send role "Allows the app to send mail as any user without a signed-in user". Every mailbox in the tenant, by default. You can narrow it — Exchange’s RBAC for Applications binds a role to a management scope, and it "replaces Application Access Policies" — but you are now asking an IT director to run PowerShell before they can try your product.
| Microsoft | ||
|---|---|---|
| Narrow grant | gmail.send (sensitive) | Delegated Mail.Send |
| Who approves it | The mailbox owner, at the consent screen | The signed-in user, subject to tenant consent policy |
| Wide grant | gmail.modify / mail.google.com (restricted) | Application Mail.Send |
| Who approves the wide grant | The mailbox owner, plus Google after a CASA assessment | A Privileged Role or Global Administrator |
| Recurring cost of the wide grant | Security assessment, generally once a year | None billed; the cost is the admin conversation |
| Publisher identity check | OAuth verification (Google, no fee) | Publisher verification (Microsoft, no fee) |
Microsoft’s identity check is publisher verification, and it is free: "Microsoft doesn’t charge developers for publisher verification. No license is required to become a verified publisher." It does require a verified Microsoft AI Cloud Partner Program account with a Partner One ID, an app registered in a work or school tenant, and a publisher domain that is not *.onmicrosoft.com. Skipping it is not neutral for a multitenant app: since November 2020, where risk-based step-up consent is enabled, users generally cannot consent to newly registered multitenant apps that are not publisher verified, and a warning about an unverified publisher appears on the consent screen.
What does a send-only scope force you to design differently?
One thing, mainly: reply handling. If you cannot read the mailbox, you cannot poll it for responses, so replies have to come back to infrastructure you control. Set Reply-To on every outbound message to an address on your own domain with your own MX, key it per thread, and ingest there. Decknative does exactly this — it holds gmail.send or delegated Mail.Send, never a read scope, and replies land on its MX rather than being fetched out of the customer’s inbox.
The cost of that design is real: you lose the ability to thread against messages the user sent by hand, and a reply sent to the From address instead of the Reply-To will not reach you. The benefit is that your scope justification writes itself, your verification is the fast lane rather than the slow one, and no assessor ever asks how you store a customer’s inbox — because you do not. Holding a read scope is not a one-time approval either: Google’s API Services User Data Policy tells developers not to "allow humans to read the data" except in a short list of cases — the user’s affirmative agreement to view specific messages, security purposes, compliance with law, or aggregated internal use — which is an obligation that outlives the review.
The same logic applies to anything else you might be tempted to reach for. On Graph, wanting a copy in Sent Items is not a reason to widen the permission — Microsoft documents that sendMail "saves the message in the Sent Items folder" on its own, and exposes a saveToSentItems flag to turn that off. Wanting to know whether the customer’s mailbox is healthy is not a reason for a read scope either; the send call’s own error responses tell you that.
What if you already shipped a restricted scope?
Check first whether you use it. Search the codebase for every Gmail endpoint you call and map each to its minimum scope from the discovery document, the same way as above. Teams frequently find that a restricted scope was requested during a prototype, kept "in case", and never called.
- Remove the scope from the authorization request and from the OAuth consent screen configuration.
- Revoke the tokens you already hold and send those users back through consent. Asking for less next time does not narrow an existing grant: Google documents that a combined authorization "includes all scopes that the user granted to the API project even if the grants were requested from different clients". POST the token to https://oauth2.googleapis.com/revoke first.
- Update the privacy policy and the demo video, because both are reviewed against the scopes you now request.
- Resubmit for verification. Sensitive-only is the shorter queue.
Common questions
- Is gmail.send a restricted scope?
- No. Google’s Gmail API scopes page lists https://www.googleapis.com/auth/gmail.send under sensitive scopes, described as "Send email on your behalf". Restricted scopes are the ones that read or fully control mail: mail.google.com, gmail.readonly, gmail.compose, gmail.modify, gmail.insert, gmail.metadata and the two gmail.settings scopes.
- Does an app using only gmail.send need a CASA security assessment?
- No. The security assessment requirement applies to apps requesting restricted scopes that can access data from or through a third-party server. An app whose only Gmail scope is gmail.send still needs OAuth verification — domain, privacy policy, homepage, demo video and a justification per scope — but not a third-party assessment.
- How much does Google charge for OAuth verification or the CASA assessment?
- Nothing. Google’s verification FAQ states that "Google does not charge the developer any fees for security assessment" and that the cost "is agreed on between the developer and the assessor without any involvement from Google". No official price exists, so any figure you see quoted is a third party’s, not Google’s, and should be confirmed with an authorised assessor.
- How long does verification take?
- Google’s own pages differ. The sensitive scope verification page says 3-5 business days; the verification FAQ says 10 business days for sensitive scopes and 6 weeks for restricted scopes, and adds that the estimates are not guaranteed. Both depend heavily on how fast you answer the reviewer’s questions.
- Can I avoid verification by keeping the app in Testing mode?
- Not for a real product. Projects in Testing are limited to 100 listed test users, and Google states that a test user’s authorization expires seven days from the time of consent, including any refresh token issued with offline access. That forces every user to reconsent weekly.
- For Microsoft 365, should I request delegated Mail.Send or application Mail.Send?
- Delegated, if a user is present to sign in. Delegated Mail.Send acts on behalf of that user and cannot exceed what the user could do. Application Mail.Send requires a Privileged Role or Global Administrator to consent and, per Exchange Online’s role table, lets the app send as any user in the tenant unless an admin scopes it with RBAC for Applications.
- Is Microsoft publisher verification required?
- Not universally, but skipping it hurts multitenant apps. Microsoft charges nothing for it. Since November 2020, where risk-based step-up consent is enabled, users generally cannot consent to newly registered multitenant apps whose publisher is unverified, and the consent screen warns them that the publisher is unverified.
Sources
- Google — Choose Gmail API scopes (sensitive vs restricted classification)
- Google — Restricted scope verification (security assessment requirement)
- Google — Sensitive scope verification (domain, privacy policy, video, justification)
- Google — OAuth app verification FAQ (assessment fees, annual cadence, timelines)
- Google — Manage your app audience (Testing status, 100 test users, 7-day expiry)
- Google — API Services User Data Policy (Limited Use requirements)
- Google — Gmail API users.messages.send reference
- Google — Sending email with the Gmail API (raw field, RFC 2822)
- Google — OAuth 2.0 for web server apps (incremental authorization, token revocation)
- App Defense Alliance — CASA framework
- Microsoft — Overview of Microsoft Graph permissions (delegated vs application)
- Microsoft — user: sendMail (permission table and examples)
- Microsoft — RBAC for Applications in Exchange Online (Application Mail.Send role)
- Microsoft — Publisher verification overview