# Gmail

Lightweight, dependency-free in-process fake of the Gmail v1 REST API for testing `googleapis` Gmail integrations with zero external side effects.

Default port: `4610`

## Implemented Operations

Profile and watch:

- `GET /gmail/v1/users/{userId}/profile` - `users.getProfile`
- `POST /gmail/v1/users/{userId}/watch` - `users.watch`
- `POST /gmail/v1/users/{userId}/stop` - `users.stop`

Messages:

- `GET /gmail/v1/users/{userId}/messages` - `users.messages.list`
- `GET /gmail/v1/users/{userId}/messages/{id}` - `users.messages.get`
- `POST /gmail/v1/users/{userId}/messages/send` - `users.messages.send`
- `POST /gmail/v1/users/{userId}/messages/import` - `users.messages.import`
- `POST /gmail/v1/users/{userId}/messages/insert` - `users.messages.insert`
- `POST /gmail/v1/users/{userId}/messages/{id}/modify` - `users.messages.modify`
- `POST /gmail/v1/users/{userId}/messages/{id}/trash` - `users.messages.trash`
- `POST /gmail/v1/users/{userId}/messages/{id}/untrash` - `users.messages.untrash`
- `DELETE /gmail/v1/users/{userId}/messages/{id}` - `users.messages.delete`
- `POST /gmail/v1/users/{userId}/messages/batchModify` - `users.messages.batchModify`
- `POST /gmail/v1/users/{userId}/messages/batchDelete` - `users.messages.batchDelete`
- `GET /gmail/v1/users/{userId}/messages/{id}/attachments/{attachmentId}` - `users.messages.attachments.get`

Drafts:

- `GET /gmail/v1/users/{userId}/drafts` - `users.drafts.list`
- `POST /gmail/v1/users/{userId}/drafts` - `users.drafts.create`
- `GET /gmail/v1/users/{userId}/drafts/{id}` - `users.drafts.get`
- `PUT /gmail/v1/users/{userId}/drafts/{id}` - `users.drafts.update`
- `POST /gmail/v1/users/{userId}/drafts/send` - `users.drafts.send`
- `DELETE /gmail/v1/users/{userId}/drafts/{id}` - `users.drafts.delete`

Threads:

- `GET /gmail/v1/users/{userId}/threads` - `users.threads.list`
- `GET /gmail/v1/users/{userId}/threads/{id}` - `users.threads.get`
- `POST /gmail/v1/users/{userId}/threads/{id}/modify` - `users.threads.modify`
- `POST /gmail/v1/users/{userId}/threads/{id}/trash` - `users.threads.trash`
- `POST /gmail/v1/users/{userId}/threads/{id}/untrash` - `users.threads.untrash`
- `DELETE /gmail/v1/users/{userId}/threads/{id}` - `users.threads.delete`

Labels and history:

- `GET /gmail/v1/users/{userId}/labels` - `users.labels.list`
- `POST /gmail/v1/users/{userId}/labels` - `users.labels.create`
- `GET /gmail/v1/users/{userId}/labels/{id}` - `users.labels.get`
- `PATCH /gmail/v1/users/{userId}/labels/{id}` - `users.labels.patch`
- `PUT /gmail/v1/users/{userId}/labels/{id}` - `users.labels.update`
- `DELETE /gmail/v1/users/{userId}/labels/{id}` - `users.labels.delete`
- `GET /gmail/v1/users/{userId}/history` - `users.history.list`

Settings:

- `GET|PUT /gmail/v1/users/{userId}/settings/autoForwarding` - `getAutoForwarding`, `updateAutoForwarding`
- `GET|PUT /gmail/v1/users/{userId}/settings/imap` - `getImap`, `updateImap`
- `GET|PUT /gmail/v1/users/{userId}/settings/language` - `getLanguage`, `updateLanguage`
- `GET|PUT /gmail/v1/users/{userId}/settings/pop` - `getPop`, `updatePop`
- `GET|PUT /gmail/v1/users/{userId}/settings/vacation` - `getVacation`, `updateVacation`
- `GET|POST|GET by id|DELETE /gmail/v1/users/{userId}/settings/filters` - filter list/create/get/delete
- `GET|POST|GET by email|DELETE /gmail/v1/users/{userId}/settings/forwardingAddresses` - forwarding address list/create/get/delete
- `GET|POST|GET by email|DELETE /gmail/v1/users/{userId}/settings/delegates` - delegate list/create/get/delete
- `GET|POST|GET by email|PATCH|PUT|DELETE /gmail/v1/users/{userId}/settings/sendAs` - send-as list/create/get/patch/update/delete
- `POST /gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}/verify` - send-as verify
- `GET|POST|GET by id|DELETE /gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}/smimeInfo` - S/MIME list/insert/get/delete
- `POST /gmail/v1/users/{userId}/settings/sendAs/{sendAsEmail}/smimeInfo/{id}/setDefault` - S/MIME set default
- `GET|POST|GET by email|PATCH|DELETE /gmail/v1/users/{userId}/settings/cse/identities` - CSE identity list/create/get/patch/delete
- `GET|POST|GET by id /gmail/v1/users/{userId}/settings/cse/keypairs` - CSE keypair list/create/get
- `POST /gmail/v1/users/{userId}/settings/cse/keypairs/{keyPairId}/disable` - CSE keypair disable
- `POST /gmail/v1/users/{userId}/settings/cse/keypairs/{keyPairId}/enable` - CSE keypair enable
- `POST /gmail/v1/users/{userId}/settings/cse/keypairs/{keyPairId}/obliterate` - CSE keypair obliterate

Upload aliases:

- `/upload/gmail/v1/...` is routed to the same handlers as `/gmail/v1/...` for media-capable `googleapis` methods.

Internal parlel endpoints:

- `GET /_parlel/health`
- `POST /_parlel/reset`

## Quick Start

```js
import { google } from "googleapis";
import { GmailServer } from "./services/gmail/src/server.js";

const server = new GmailServer(4610);
await server.start();

const gmail = google.gmail({ version: "v1", auth: "fake-token" });
gmail.context._options.rootUrl = "http://127.0.0.1:4610/";

const created = await gmail.users.messages.insert({
  userId: "me",
  requestBody: {
    raw: Buffer.from("Subject: hi\r\n\r\nhello").toString("base64url"),
    labelIds: ["INBOX"],
  },
});

console.log(created.data.id);
await server.stop();
```

## Support Matrix

| Feature | Status | Notes |
| --- | --- | --- |
| Gmail v1 JSON REST paths used by `googleapis` | Supported | Includes `/gmail/v1` and `/upload/gmail/v1` routing. |
| In-memory messages, drafts, threads, labels, history | Supported | Ephemeral and resettable. |
| Settings resources | Supported | Auto-forwarding, IMAP, language, POP, vacation, filters, forwarding addresses, delegates, send-as, S/MIME, CSE. |
| Message formats | Supported | `full`, `metadata`, `minimal`, and `raw`. |
| List pagination | Supported | `maxResults` and `pageToken`. |
| Basic Gmail query filtering | Supported | Supports `from:`, `to:`, `subject:`, and substring matching. |
| OAuth and IAM enforcement | Intentionally unsupported | Any token is accepted; this is a local fake. |
| Real email delivery or Pub/Sub delivery | Intentionally unsupported | `send` and `watch` mutate local state only. |
| MIME parsing fidelity | Intentionally lightweight | Header/body parsing is realistic enough for client tests, not a full MIME implementation. |
| Persistent storage | Intentionally unsupported | State is process-local and resettable. |

## Error Shapes

Errors use the Gmail/Google JSON API envelope:

```json
{
  "error": {
    "code": 404,
    "message": "Message not found",
    "errors": [
      { "message": "Message not found", "domain": "global", "reason": "notFound" }
    ],
    "status": "NOTFOUND"
  }
}
```

Common returned codes:

| HTTP | Reason | Typical cause |
| --- | --- | --- |
| `400` | `invalidArgument` | Missing required fields such as `topicName` or invalid label mutation. |
| `404` | `notFound` | Missing user resource, message, draft, thread, label, or settings child resource. |
| `405` | `methodNotAllowed` | Valid endpoint with unsupported HTTP method. |
| `500` | `backendError` | Unexpected server exception. |
