msoutlook-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -0
- package/dist/api/calendar.d.ts +90 -0
- package/dist/api/calendar.d.ts.map +1 -0
- package/dist/api/calendar.js +102 -0
- package/dist/api/calendar.js.map +1 -0
- package/dist/api/client.d.ts +14 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +93 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/contacts.d.ts +43 -0
- package/dist/api/contacts.d.ts.map +1 -0
- package/dist/api/contacts.js +45 -0
- package/dist/api/contacts.js.map +1 -0
- package/dist/api/mail.d.ts +90 -0
- package/dist/api/mail.d.ts.map +1 -0
- package/dist/api/mail.js +148 -0
- package/dist/api/mail.js.map +1 -0
- package/dist/api/people.d.ts +28 -0
- package/dist/api/people.d.ts.map +1 -0
- package/dist/api/people.js +16 -0
- package/dist/api/people.js.map +1 -0
- package/dist/auth/browser-login.d.ts +26 -0
- package/dist/auth/browser-login.d.ts.map +1 -0
- package/dist/auth/browser-login.js +398 -0
- package/dist/auth/browser-login.js.map +1 -0
- package/dist/auth/index.d.ts +34 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +89 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/session-store.d.ts +38 -0
- package/dist/auth/session-store.d.ts.map +1 -0
- package/dist/auth/session-store.js +163 -0
- package/dist/auth/session-store.js.map +1 -0
- package/dist/auth/token-extractor.d.ts +46 -0
- package/dist/auth/token-extractor.d.ts.map +1 -0
- package/dist/auth/token-extractor.js +126 -0
- package/dist/auth/token-extractor.js.map +1 -0
- package/dist/auth/token-refresh.d.ts +23 -0
- package/dist/auth/token-refresh.d.ts.map +1 -0
- package/dist/auth/token-refresh.js +133 -0
- package/dist/auth/token-refresh.js.map +1 -0
- package/dist/browser/cookie-import.d.ts +30 -0
- package/dist/browser/cookie-import.d.ts.map +1 -0
- package/dist/browser/cookie-import.js +446 -0
- package/dist/browser/cookie-import.js.map +1 -0
- package/dist/constants.d.ts +27 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +39 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +20 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/auth-tools.d.ts +6 -0
- package/dist/tools/auth-tools.d.ts.map +1 -0
- package/dist/tools/auth-tools.js +116 -0
- package/dist/tools/auth-tools.js.map +1 -0
- package/dist/tools/calendar-tools.d.ts +6 -0
- package/dist/tools/calendar-tools.d.ts.map +1 -0
- package/dist/tools/calendar-tools.js +168 -0
- package/dist/tools/calendar-tools.js.map +1 -0
- package/dist/tools/contact-tools.d.ts +6 -0
- package/dist/tools/contact-tools.d.ts.map +1 -0
- package/dist/tools/contact-tools.js +105 -0
- package/dist/tools/contact-tools.js.map +1 -0
- package/dist/tools/mail-tools.d.ts +6 -0
- package/dist/tools/mail-tools.d.ts.map +1 -0
- package/dist/tools/mail-tools.js +196 -0
- package/dist/tools/mail-tools.js.map +1 -0
- package/dist/utils/http.d.ts +15 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +48 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +21 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# msoutlook-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for Microsoft Outlook Web — no app registration required.
|
|
4
|
+
|
|
5
|
+
Uses your existing Outlook Web session (the same way [msteams-mcp](https://github.com/m0nkmaster/msteams-mcp) uses the Teams web session). Opens a browser once for login, then caches tokens and refreshes them automatically.
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
Microsoft Outlook Web (OWA) uses MSAL to store OAuth tokens in `localStorage`. This server:
|
|
10
|
+
|
|
11
|
+
1. Opens a browser to `outlook.office.com` via Playwright
|
|
12
|
+
2. Extracts the MSAL token cache from `localStorage` — using OWA's own first-party client ID (`9199bf20-a13f-4107-85dc-02114787ef48`)
|
|
13
|
+
3. Caches the access token, refresh token, and session state in `~/.msoutlook-mcp-server/` (AES-256-GCM encrypted)
|
|
14
|
+
4. Refreshes tokens automatically using the refresh token (HTTP, no browser) or headless browser as fallback
|
|
15
|
+
|
|
16
|
+
No Azure app registration. No admin consent. No client secrets. Your access is limited to what your account can already do.
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"outlook": {
|
|
24
|
+
"command": "npx",
|
|
25
|
+
"args": ["-y", "msoutlook-mcp@latest"]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then run `outlook_login` from your MCP client to open the browser and authenticate.
|
|
32
|
+
|
|
33
|
+
## Tools
|
|
34
|
+
|
|
35
|
+
### Auth
|
|
36
|
+
|
|
37
|
+
| Tool | Description |
|
|
38
|
+
|------|-------------|
|
|
39
|
+
| `outlook_login` | Open browser to sign in to Outlook Web |
|
|
40
|
+
| `outlook_status` | Check authentication status and token validity |
|
|
41
|
+
| `outlook_logout` | Clear saved session and tokens |
|
|
42
|
+
|
|
43
|
+
### Email
|
|
44
|
+
|
|
45
|
+
| Tool | Description |
|
|
46
|
+
|------|-------------|
|
|
47
|
+
| `outlook_list_emails` | List emails from any folder (Inbox by default) |
|
|
48
|
+
| `outlook_get_email` | Read full email content by ID |
|
|
49
|
+
| `outlook_get_unread` | Get unread emails from Inbox |
|
|
50
|
+
| `outlook_search_emails` | Search emails by keyword |
|
|
51
|
+
| `outlook_send_email` | Send an email |
|
|
52
|
+
| `outlook_create_draft` | Create a draft without sending |
|
|
53
|
+
| `outlook_send_draft` | Send a previously created draft |
|
|
54
|
+
| `outlook_reply` | Reply to an email (or reply all) |
|
|
55
|
+
| `outlook_forward` | Forward an email |
|
|
56
|
+
| `outlook_mark_read` | Mark email as read or unread |
|
|
57
|
+
| `outlook_flag` | Flag or unflag an email |
|
|
58
|
+
| `outlook_move_email` | Move email to a different folder |
|
|
59
|
+
| `outlook_delete_email` | Delete an email |
|
|
60
|
+
| `outlook_list_folders` | List all mail folders with unread counts |
|
|
61
|
+
|
|
62
|
+
### Calendar
|
|
63
|
+
|
|
64
|
+
| Tool | Description |
|
|
65
|
+
|------|-------------|
|
|
66
|
+
| `outlook_list_events` | List calendar events in a date range |
|
|
67
|
+
| `outlook_get_event` | Get full event details including attendees |
|
|
68
|
+
| `outlook_create_event` | Create a meeting or appointment |
|
|
69
|
+
| `outlook_update_event` | Update an existing event |
|
|
70
|
+
| `outlook_delete_event` | Delete an event |
|
|
71
|
+
| `outlook_respond_to_event` | Accept, decline, or tentatively accept an invite |
|
|
72
|
+
| `outlook_search_events` | Search events by keyword |
|
|
73
|
+
| `outlook_list_calendars` | List all calendars |
|
|
74
|
+
|
|
75
|
+
### Contacts & People
|
|
76
|
+
|
|
77
|
+
| Tool | Description |
|
|
78
|
+
|------|-------------|
|
|
79
|
+
| `outlook_list_contacts` | List/search contacts |
|
|
80
|
+
| `outlook_get_contact` | Get contact details by ID |
|
|
81
|
+
| `outlook_create_contact` | Create a new contact |
|
|
82
|
+
| `outlook_delete_contact` | Delete a contact |
|
|
83
|
+
| `outlook_search_people` | Search the organisation directory |
|
|
84
|
+
|
|
85
|
+
## Session storage
|
|
86
|
+
|
|
87
|
+
Session files are stored encrypted in `~/.msoutlook-mcp-server/`:
|
|
88
|
+
|
|
89
|
+
- `session-state.json` — Playwright browser session (cookies + localStorage)
|
|
90
|
+
- `token-cache.json` — Extracted and cached tokens
|
|
91
|
+
- `browser-profile/` — Persistent browser profile for headless refresh
|
|
92
|
+
|
|
93
|
+
If your session expires, run `outlook_login` again.
|
|
94
|
+
|
|
95
|
+
## Token refresh
|
|
96
|
+
|
|
97
|
+
Tokens are refreshed automatically:
|
|
98
|
+
|
|
99
|
+
1. **HTTP refresh** (fast, no browser) — uses the cached refresh token with OWA's client ID
|
|
100
|
+
2. **Headless browser refresh** — fallback if HTTP refresh fails; opens a headless Edge window to silently re-acquire tokens from the saved browser session
|
|
101
|
+
|
|
102
|
+
## Requirements
|
|
103
|
+
|
|
104
|
+
- Node.js 20+
|
|
105
|
+
- A Chromium-based browser: Edge or Chrome (auto-detected from system default)
|
|
106
|
+
- A Microsoft 365 work/school account or personal Microsoft account
|
|
107
|
+
|
|
108
|
+
## Platform support
|
|
109
|
+
|
|
110
|
+
| Feature | macOS | Linux | Windows |
|
|
111
|
+
|---------|-------|-------|---------|
|
|
112
|
+
| Browser auto-detection | System default (Edge/Chrome) | Chrome fallback | Edge (pre-installed) |
|
|
113
|
+
| SSO cookie import | ✅ Chrome + Edge via Keychain | ✅ Chrome + Edge via libsecret / `"peanuts"` fallback | ✅ Edge via DPAPI (PowerShell) |
|
|
114
|
+
| Windows Chrome 127+ cookies | — | — | ⚠️ App-Bound Encryption — not supported. Use Edge instead. |
|
|
115
|
+
| Headed browser fallback | ✅ | ✅ | ✅ |
|
|
116
|
+
|
|
117
|
+
Cookie import is a best-effort optimisation. If it cannot run (e.g. no matching browser installed, Keychain denied), the MCP falls back to opening a headed browser where you sign in once manually — the session then persists.
|
|
118
|
+
|
|
119
|
+
## Security notes
|
|
120
|
+
|
|
121
|
+
- Uses the same auth as the Outlook web client — your access is limited to what your account can do
|
|
122
|
+
- Tokens are encrypted at rest (AES-256-GCM with a machine-derived key)
|
|
123
|
+
- Uses undocumented internal APIs — Microsoft may change these without notice
|
|
124
|
+
- Always confirm email content with the user before sending
|
|
125
|
+
|
|
126
|
+
## Environment variables
|
|
127
|
+
|
|
128
|
+
| Variable | Description |
|
|
129
|
+
|----------|-------------|
|
|
130
|
+
| `MSOUTLOOK_DEBUG=true` | Enable debug logging to stderr |
|
|
131
|
+
| `MSOUTLOOK_BROWSER=chrome` | Force a specific browser: `chrome` or `msedge`. If unset, uses the macOS system default browser; falls back to Chrome on macOS/Linux and Edge on Windows. |
|
|
132
|
+
| `MSOUTLOOK_CHROME_PROFILE` | Pin a specific Chrome profile dir for cookie import (e.g. `Profile 1`). Defaults to `Default`. |
|
|
133
|
+
| `MSOUTLOOK_EDGE_PROFILE` | Pin a specific Edge profile dir for cookie import (e.g. `Profile 1`). Defaults to `Default`. |
|
|
134
|
+
| `MSOUTLOOK_SKIP_COOKIE_IMPORT=true` | Skip importing SSO cookies from your real browser (avoids the one-time Keychain/keyring prompt). You'll sign in once manually in the browser; the persistent profile then remembers the session. |
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar API — events, meetings, and availability.
|
|
3
|
+
*/
|
|
4
|
+
import type { Recipient } from './mail.js';
|
|
5
|
+
export interface DateTimeTimeZone {
|
|
6
|
+
DateTime: string;
|
|
7
|
+
TimeZone: string;
|
|
8
|
+
}
|
|
9
|
+
export interface Attendee {
|
|
10
|
+
EmailAddress: {
|
|
11
|
+
Name?: string;
|
|
12
|
+
Address: string;
|
|
13
|
+
};
|
|
14
|
+
Type?: 'Required' | 'Optional' | 'Resource';
|
|
15
|
+
Status?: {
|
|
16
|
+
Response: string;
|
|
17
|
+
Time: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface CalendarEvent {
|
|
21
|
+
Id: string;
|
|
22
|
+
Subject: string;
|
|
23
|
+
BodyPreview?: string;
|
|
24
|
+
Body?: {
|
|
25
|
+
ContentType: string;
|
|
26
|
+
Content: string;
|
|
27
|
+
};
|
|
28
|
+
Start: DateTimeTimeZone;
|
|
29
|
+
End: DateTimeTimeZone;
|
|
30
|
+
Location?: {
|
|
31
|
+
DisplayName: string;
|
|
32
|
+
};
|
|
33
|
+
Organizer?: Recipient;
|
|
34
|
+
Attendees?: Attendee[];
|
|
35
|
+
IsAllDay?: boolean;
|
|
36
|
+
IsCancelled?: boolean;
|
|
37
|
+
IsOnlineMeeting?: boolean;
|
|
38
|
+
OnlineMeetingUrl?: string;
|
|
39
|
+
Recurrence?: unknown;
|
|
40
|
+
Importance?: string;
|
|
41
|
+
Sensitivity?: string;
|
|
42
|
+
ShowAs?: string;
|
|
43
|
+
WebLink?: string;
|
|
44
|
+
ResponseStatus?: {
|
|
45
|
+
Response: string;
|
|
46
|
+
Time: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export interface Calendar {
|
|
50
|
+
Id: string;
|
|
51
|
+
Name: string;
|
|
52
|
+
Color?: string;
|
|
53
|
+
IsDefaultCalendar?: boolean;
|
|
54
|
+
CanEdit?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface ListEventsOptions {
|
|
57
|
+
calendarId?: string;
|
|
58
|
+
startDateTime?: string;
|
|
59
|
+
endDateTime?: string;
|
|
60
|
+
top?: number;
|
|
61
|
+
filter?: string;
|
|
62
|
+
select?: string[];
|
|
63
|
+
}
|
|
64
|
+
export declare function listEvents(opts?: ListEventsOptions): Promise<CalendarEvent[]>;
|
|
65
|
+
export declare function getEvent(id: string): Promise<CalendarEvent>;
|
|
66
|
+
export interface CreateEventOptions {
|
|
67
|
+
subject: string;
|
|
68
|
+
body?: string;
|
|
69
|
+
bodyType?: 'Text' | 'HTML';
|
|
70
|
+
start: string;
|
|
71
|
+
end: string;
|
|
72
|
+
timeZone?: string;
|
|
73
|
+
location?: string;
|
|
74
|
+
attendees?: Array<{
|
|
75
|
+
email: string;
|
|
76
|
+
name?: string;
|
|
77
|
+
type?: 'Required' | 'Optional';
|
|
78
|
+
}>;
|
|
79
|
+
isOnlineMeeting?: boolean;
|
|
80
|
+
importance?: 'Low' | 'Normal' | 'High';
|
|
81
|
+
isAllDay?: boolean;
|
|
82
|
+
}
|
|
83
|
+
export declare function createEvent(opts: CreateEventOptions): Promise<CalendarEvent>;
|
|
84
|
+
export declare function updateEvent(id: string, updates: Partial<CreateEventOptions>): Promise<CalendarEvent>;
|
|
85
|
+
export declare function deleteEvent(id: string): Promise<void>;
|
|
86
|
+
export type EventResponse = 'accept' | 'decline' | 'tentativelyAccept';
|
|
87
|
+
export declare function respondToEvent(id: string, response: EventResponse, comment?: string): Promise<void>;
|
|
88
|
+
export declare function searchEvents(query: string, fromDate?: string, toDate?: string): Promise<CalendarEvent[]>;
|
|
89
|
+
export declare function listCalendars(): Promise<Calendar[]>;
|
|
90
|
+
//# sourceMappingURL=calendar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../src/api/calendar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar API — events, meetings, and availability.
|
|
3
|
+
*/
|
|
4
|
+
import { owaGet, owaPost, owaPatch, owaDelete } from './client.js';
|
|
5
|
+
export async function listEvents(opts = {}) {
|
|
6
|
+
const path = opts.calendarId ? `/calendars/${opts.calendarId}/calendarview` : '/calendarview';
|
|
7
|
+
const now = new Date();
|
|
8
|
+
const weekOut = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
|
|
9
|
+
const params = {
|
|
10
|
+
startDateTime: opts.startDateTime ?? now.toISOString(),
|
|
11
|
+
endDateTime: opts.endDateTime ?? weekOut.toISOString(),
|
|
12
|
+
'$top': String(opts.top ?? 50),
|
|
13
|
+
'$orderby': 'start/dateTime asc',
|
|
14
|
+
'$select': (opts.select ?? [
|
|
15
|
+
'Id', 'Subject', 'BodyPreview', 'Start', 'End', 'Location',
|
|
16
|
+
'Organizer', 'Attendees', 'IsAllDay', 'IsCancelled', 'IsOnlineMeeting',
|
|
17
|
+
'OnlineMeetingUrl', 'ResponseStatus', 'WebLink',
|
|
18
|
+
]).join(','),
|
|
19
|
+
};
|
|
20
|
+
if (opts.filter)
|
|
21
|
+
params['$filter'] = opts.filter;
|
|
22
|
+
const res = await owaGet(path, params);
|
|
23
|
+
return res.value;
|
|
24
|
+
}
|
|
25
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
26
|
+
// Get event
|
|
27
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
28
|
+
export async function getEvent(id) {
|
|
29
|
+
return owaGet(`/events/${id}`);
|
|
30
|
+
}
|
|
31
|
+
export async function createEvent(opts) {
|
|
32
|
+
const tz = opts.timeZone ?? 'UTC';
|
|
33
|
+
const attendees = opts.attendees?.map(a => ({
|
|
34
|
+
EmailAddress: { Address: a.email, Name: a.name ?? a.email },
|
|
35
|
+
Type: a.type ?? 'Required',
|
|
36
|
+
}));
|
|
37
|
+
return owaPost('/events', {
|
|
38
|
+
Subject: opts.subject,
|
|
39
|
+
Body: { ContentType: opts.bodyType ?? 'Text', Content: opts.body ?? '' },
|
|
40
|
+
Start: { DateTime: opts.start, TimeZone: tz },
|
|
41
|
+
End: { DateTime: opts.end, TimeZone: tz },
|
|
42
|
+
...(opts.location ? { Location: { DisplayName: opts.location } } : {}),
|
|
43
|
+
...(attendees?.length ? { Attendees: attendees } : {}),
|
|
44
|
+
IsOnlineMeeting: opts.isOnlineMeeting ?? false,
|
|
45
|
+
Importance: opts.importance ?? 'Normal',
|
|
46
|
+
IsAllDay: opts.isAllDay ?? false,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
50
|
+
// Update event
|
|
51
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
52
|
+
export async function updateEvent(id, updates) {
|
|
53
|
+
const tz = updates.timeZone ?? 'UTC';
|
|
54
|
+
const body = {};
|
|
55
|
+
if (updates.subject !== undefined)
|
|
56
|
+
body.Subject = updates.subject;
|
|
57
|
+
if (updates.body !== undefined) {
|
|
58
|
+
body.Body = { ContentType: updates.bodyType ?? 'Text', Content: updates.body };
|
|
59
|
+
}
|
|
60
|
+
if (updates.start !== undefined)
|
|
61
|
+
body.Start = { DateTime: updates.start, TimeZone: tz };
|
|
62
|
+
if (updates.end !== undefined)
|
|
63
|
+
body.End = { DateTime: updates.end, TimeZone: tz };
|
|
64
|
+
if (updates.location !== undefined)
|
|
65
|
+
body.Location = { DisplayName: updates.location };
|
|
66
|
+
if (updates.isOnlineMeeting !== undefined)
|
|
67
|
+
body.IsOnlineMeeting = updates.isOnlineMeeting;
|
|
68
|
+
return owaPatch(`/events/${id}`, body);
|
|
69
|
+
}
|
|
70
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
71
|
+
// Delete event
|
|
72
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
73
|
+
export async function deleteEvent(id) {
|
|
74
|
+
await owaDelete(`/events/${id}`);
|
|
75
|
+
}
|
|
76
|
+
export async function respondToEvent(id, response, comment) {
|
|
77
|
+
await owaPost(`/events/${id}/${response}`, {
|
|
78
|
+
Comment: comment ?? '',
|
|
79
|
+
SendResponse: true,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
83
|
+
// Search events
|
|
84
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
85
|
+
export async function searchEvents(query, fromDate, toDate) {
|
|
86
|
+
return listEvents({
|
|
87
|
+
startDateTime: fromDate,
|
|
88
|
+
endDateTime: toDate,
|
|
89
|
+
filter: `contains(subject,'${query.replace(/'/g, "''")}')`,
|
|
90
|
+
top: 25,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
94
|
+
// Calendars
|
|
95
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
96
|
+
export async function listCalendars() {
|
|
97
|
+
const res = await owaGet('/calendars', {
|
|
98
|
+
'$select': 'Id,Name,Color,IsDefaultCalendar,CanEdit',
|
|
99
|
+
});
|
|
100
|
+
return res.value;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=calendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.js","sourceRoot":"","sources":["../../src/api/calendar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base API client for Outlook Web API calls.
|
|
3
|
+
*
|
|
4
|
+
* Uses the OWA REST API v2 (https://outlook.office.com/api/v2.0/me/...)
|
|
5
|
+
* which is the same API the Outlook mobile and web clients use internally.
|
|
6
|
+
* The token from the OWA session grants access to all required scopes.
|
|
7
|
+
*/
|
|
8
|
+
export declare function owaGet<T>(path: string, params?: Record<string, string>): Promise<T>;
|
|
9
|
+
export declare function owaPost<T>(path: string, body: unknown): Promise<T>;
|
|
10
|
+
export declare function owaPatch<T>(path: string, body: unknown): Promise<T>;
|
|
11
|
+
export declare function owaDelete(path: string): Promise<void>;
|
|
12
|
+
export declare function graphGet<T>(path: string, params?: Record<string, string>): Promise<T>;
|
|
13
|
+
export declare function graphPost<T>(path: string, body: unknown): Promise<T>;
|
|
14
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,wBAAsB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAezF;AAED,wBAAsB,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAUxE;AAED,wBAAsB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAUzE;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY3D;AAMD,wBAAsB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAe3F;AAED,wBAAsB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAU1E"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base API client for Outlook Web API calls.
|
|
3
|
+
*
|
|
4
|
+
* Uses the OWA REST API v2 (https://outlook.office.com/api/v2.0/me/...)
|
|
5
|
+
* which is the same API the Outlook mobile and web clients use internally.
|
|
6
|
+
* The token from the OWA session grants access to all required scopes.
|
|
7
|
+
*/
|
|
8
|
+
import { getOwaToken, getGraphToken } from '../auth/index.js';
|
|
9
|
+
import { OWA_REST_V2, GRAPH_BASE, OWA_BASE } from '../constants.js';
|
|
10
|
+
import { getBearerHeaders, parseResponse, fetchWithRetry } from '../utils/http.js';
|
|
11
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
// OWA REST API client
|
|
13
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
export async function owaGet(path, params) {
|
|
15
|
+
const token = await getOwaToken();
|
|
16
|
+
if (!token)
|
|
17
|
+
throw new Error('Not authenticated. Run outlook_login first.');
|
|
18
|
+
let url = `${OWA_REST_V2}/me${path}`;
|
|
19
|
+
if (params) {
|
|
20
|
+
const qs = new URLSearchParams(params).toString();
|
|
21
|
+
url += (url.includes('?') ? '&' : '?') + qs;
|
|
22
|
+
}
|
|
23
|
+
const res = await fetchWithRetry(url, {
|
|
24
|
+
method: 'GET',
|
|
25
|
+
headers: getBearerHeaders(token, OWA_BASE),
|
|
26
|
+
});
|
|
27
|
+
return parseResponse(res);
|
|
28
|
+
}
|
|
29
|
+
export async function owaPost(path, body) {
|
|
30
|
+
const token = await getOwaToken();
|
|
31
|
+
if (!token)
|
|
32
|
+
throw new Error('Not authenticated. Run outlook_login first.');
|
|
33
|
+
const res = await fetchWithRetry(`${OWA_REST_V2}/me${path}`, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: getBearerHeaders(token, OWA_BASE),
|
|
36
|
+
body: JSON.stringify(body),
|
|
37
|
+
});
|
|
38
|
+
return parseResponse(res);
|
|
39
|
+
}
|
|
40
|
+
export async function owaPatch(path, body) {
|
|
41
|
+
const token = await getOwaToken();
|
|
42
|
+
if (!token)
|
|
43
|
+
throw new Error('Not authenticated. Run outlook_login first.');
|
|
44
|
+
const res = await fetchWithRetry(`${OWA_REST_V2}/me${path}`, {
|
|
45
|
+
method: 'PATCH',
|
|
46
|
+
headers: getBearerHeaders(token, OWA_BASE),
|
|
47
|
+
body: JSON.stringify(body),
|
|
48
|
+
});
|
|
49
|
+
return parseResponse(res);
|
|
50
|
+
}
|
|
51
|
+
export async function owaDelete(path) {
|
|
52
|
+
const token = await getOwaToken();
|
|
53
|
+
if (!token)
|
|
54
|
+
throw new Error('Not authenticated. Run outlook_login first.');
|
|
55
|
+
const res = await fetchWithRetry(`${OWA_REST_V2}/me${path}`, {
|
|
56
|
+
method: 'DELETE',
|
|
57
|
+
headers: getBearerHeaders(token, OWA_BASE),
|
|
58
|
+
});
|
|
59
|
+
if (!res.ok && res.status !== 204) {
|
|
60
|
+
const text = await res.text().catch(() => '');
|
|
61
|
+
throw new Error(`HTTP ${res.status}: ${text.slice(0, 200)}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
65
|
+
// Graph API client (fallback for some endpoints)
|
|
66
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
67
|
+
export async function graphGet(path, params) {
|
|
68
|
+
const token = await getGraphToken();
|
|
69
|
+
if (!token)
|
|
70
|
+
throw new Error('Graph token unavailable. Run outlook_login first.');
|
|
71
|
+
let url = `${GRAPH_BASE}/me${path}`;
|
|
72
|
+
if (params) {
|
|
73
|
+
const qs = new URLSearchParams(params).toString();
|
|
74
|
+
url += (url.includes('?') ? '&' : '?') + qs;
|
|
75
|
+
}
|
|
76
|
+
const res = await fetchWithRetry(url, {
|
|
77
|
+
method: 'GET',
|
|
78
|
+
headers: getBearerHeaders(token),
|
|
79
|
+
});
|
|
80
|
+
return parseResponse(res);
|
|
81
|
+
}
|
|
82
|
+
export async function graphPost(path, body) {
|
|
83
|
+
const token = await getGraphToken();
|
|
84
|
+
if (!token)
|
|
85
|
+
throw new Error('Graph token unavailable. Run outlook_login first.');
|
|
86
|
+
const res = await fetchWithRetry(`${GRAPH_BASE}/me${path}`, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
headers: getBearerHeaders(token),
|
|
89
|
+
body: JSON.stringify(body),
|
|
90
|
+
});
|
|
91
|
+
return parseResponse(res);
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contacts API.
|
|
3
|
+
*/
|
|
4
|
+
export interface Contact {
|
|
5
|
+
Id: string;
|
|
6
|
+
DisplayName: string;
|
|
7
|
+
GivenName?: string;
|
|
8
|
+
Surname?: string;
|
|
9
|
+
EmailAddresses?: Array<{
|
|
10
|
+
Name?: string;
|
|
11
|
+
Address: string;
|
|
12
|
+
}>;
|
|
13
|
+
BusinessPhones?: string[];
|
|
14
|
+
MobilePhone?: string;
|
|
15
|
+
JobTitle?: string;
|
|
16
|
+
CompanyName?: string;
|
|
17
|
+
Department?: string;
|
|
18
|
+
OfficeLocation?: string;
|
|
19
|
+
BusinessAddress?: {
|
|
20
|
+
Street?: string;
|
|
21
|
+
City?: string;
|
|
22
|
+
State?: string;
|
|
23
|
+
CountryOrRegion?: string;
|
|
24
|
+
PostalCode?: string;
|
|
25
|
+
};
|
|
26
|
+
Notes?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function listContacts(search?: string, top?: number): Promise<Contact[]>;
|
|
29
|
+
export declare function getContact(id: string): Promise<Contact>;
|
|
30
|
+
export interface CreateContactOptions {
|
|
31
|
+
givenName?: string;
|
|
32
|
+
surname?: string;
|
|
33
|
+
displayName?: string;
|
|
34
|
+
email?: string;
|
|
35
|
+
businessPhone?: string;
|
|
36
|
+
mobilePhone?: string;
|
|
37
|
+
jobTitle?: string;
|
|
38
|
+
companyName?: string;
|
|
39
|
+
notes?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function createContact(opts: CreateContactOptions): Promise<Contact>;
|
|
42
|
+
export declare function deleteContact(id: string): Promise<void>;
|
|
43
|
+
//# sourceMappingURL=contacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contacts.d.ts","sourceRoot":"","sources":["../../src/api/contacts.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAsB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAWhF;AAMD,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE7D;AAMD,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,CAchF;AAMD,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contacts API.
|
|
3
|
+
*/
|
|
4
|
+
import { owaGet, owaPost, owaDelete } from './client.js';
|
|
5
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
// List contacts
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
export async function listContacts(search, top = 25) {
|
|
9
|
+
const params = {
|
|
10
|
+
'$top': String(top),
|
|
11
|
+
'$orderby': 'displayName asc',
|
|
12
|
+
'$select': 'Id,DisplayName,GivenName,Surname,EmailAddresses,BusinessPhones,MobilePhone,JobTitle,CompanyName',
|
|
13
|
+
};
|
|
14
|
+
if (search)
|
|
15
|
+
params['$search'] = `"${search}"`;
|
|
16
|
+
const res = await owaGet('/contacts', params);
|
|
17
|
+
return res.value;
|
|
18
|
+
}
|
|
19
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
// Get contact
|
|
21
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
+
export async function getContact(id) {
|
|
23
|
+
return owaGet(`/contacts/${id}`);
|
|
24
|
+
}
|
|
25
|
+
export async function createContact(opts) {
|
|
26
|
+
const emailAddresses = opts.email ? [{ Address: opts.email }] : undefined;
|
|
27
|
+
return owaPost('/contacts', {
|
|
28
|
+
GivenName: opts.givenName,
|
|
29
|
+
Surname: opts.surname,
|
|
30
|
+
DisplayName: opts.displayName ?? `${opts.givenName ?? ''} ${opts.surname ?? ''}`.trim(),
|
|
31
|
+
...(emailAddresses ? { EmailAddresses: emailAddresses } : {}),
|
|
32
|
+
...(opts.businessPhone ? { BusinessPhones: [opts.businessPhone] } : {}),
|
|
33
|
+
MobilePhone: opts.mobilePhone,
|
|
34
|
+
JobTitle: opts.jobTitle,
|
|
35
|
+
CompanyName: opts.companyName,
|
|
36
|
+
PersonalNotes: opts.notes,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
40
|
+
// Delete contact
|
|
41
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
42
|
+
export async function deleteContact(id) {
|
|
43
|
+
await owaDelete(`/contacts/${id}`);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=contacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contacts.js","sourceRoot":"","sources":["../../src/api/contacts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AA6BzD,gFAAgF;AAChF,gBAAgB;AAChB,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAe,EAAE,GAAG,GAAG,EAAE;IAC1D,MAAM,MAAM,GAA2B;QACrC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC;QACnB,UAAU,EAAE,iBAAiB;QAC7B,SAAS,EAAE,iGAAiG;KAC7G,CAAC;IAEF,IAAI,MAAM;QAAE,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,MAAM,GAAG,CAAC;IAE9C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAyB,WAAW,EAAE,MAAM,CAAC,CAAC;IACtE,OAAO,GAAG,CAAC,KAAK,CAAC;AACnB,CAAC;AAED,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,EAAU;IACzC,OAAO,MAAM,CAAU,aAAa,EAAE,EAAE,CAAC,CAAC;AAC5C,CAAC;AAkBD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAA0B;IAC5D,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE1E,OAAO,OAAO,CAAU,WAAW,EAAE;QACnC,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;QACvF,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,aAAa,EAAE,IAAI,CAAC,KAAK;KAC1B,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAU;IAC5C,MAAM,SAAS,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mail API — email CRUD, search, and folder operations.
|
|
3
|
+
*/
|
|
4
|
+
export interface EmailAddress {
|
|
5
|
+
Name: string;
|
|
6
|
+
Address: string;
|
|
7
|
+
}
|
|
8
|
+
export interface Recipient {
|
|
9
|
+
EmailAddress: EmailAddress;
|
|
10
|
+
}
|
|
11
|
+
export interface Message {
|
|
12
|
+
Id: string;
|
|
13
|
+
Subject: string;
|
|
14
|
+
BodyPreview?: string;
|
|
15
|
+
Body?: {
|
|
16
|
+
ContentType: string;
|
|
17
|
+
Content: string;
|
|
18
|
+
};
|
|
19
|
+
From?: Recipient;
|
|
20
|
+
Sender?: Recipient;
|
|
21
|
+
ToRecipients?: Recipient[];
|
|
22
|
+
CcRecipients?: Recipient[];
|
|
23
|
+
BccRecipients?: Recipient[];
|
|
24
|
+
ReceivedDateTime?: string;
|
|
25
|
+
SentDateTime?: string;
|
|
26
|
+
IsRead?: boolean;
|
|
27
|
+
HasAttachments?: boolean;
|
|
28
|
+
Importance?: string;
|
|
29
|
+
Flag?: {
|
|
30
|
+
FlagStatus: string;
|
|
31
|
+
};
|
|
32
|
+
ConversationId?: string;
|
|
33
|
+
ParentFolderId?: string;
|
|
34
|
+
WebLink?: string;
|
|
35
|
+
Attachments?: Attachment[];
|
|
36
|
+
}
|
|
37
|
+
export interface Attachment {
|
|
38
|
+
Id: string;
|
|
39
|
+
Name: string;
|
|
40
|
+
ContentType: string;
|
|
41
|
+
Size: number;
|
|
42
|
+
IsInline: boolean;
|
|
43
|
+
}
|
|
44
|
+
export interface MailFolder {
|
|
45
|
+
Id: string;
|
|
46
|
+
DisplayName: string;
|
|
47
|
+
UnreadItemCount: number;
|
|
48
|
+
TotalItemCount: number;
|
|
49
|
+
ChildFolderCount: number;
|
|
50
|
+
}
|
|
51
|
+
export interface ODataResponse<T> {
|
|
52
|
+
value: T[];
|
|
53
|
+
'@odata.nextLink'?: string;
|
|
54
|
+
'@odata.count'?: number;
|
|
55
|
+
}
|
|
56
|
+
export interface ListMessagesOptions {
|
|
57
|
+
folder?: string;
|
|
58
|
+
top?: number;
|
|
59
|
+
skip?: number;
|
|
60
|
+
filter?: string;
|
|
61
|
+
select?: string[];
|
|
62
|
+
orderBy?: string;
|
|
63
|
+
search?: string;
|
|
64
|
+
}
|
|
65
|
+
export declare function listMessages(opts?: ListMessagesOptions): Promise<Message[]>;
|
|
66
|
+
export declare function getMessage(id: string, includeAttachments?: boolean): Promise<Message>;
|
|
67
|
+
export interface SendEmailOptions {
|
|
68
|
+
to: string[];
|
|
69
|
+
cc?: string[];
|
|
70
|
+
bcc?: string[];
|
|
71
|
+
subject: string;
|
|
72
|
+
body: string;
|
|
73
|
+
bodyType?: 'Text' | 'HTML';
|
|
74
|
+
importance?: 'Low' | 'Normal' | 'High';
|
|
75
|
+
saveToSentItems?: boolean;
|
|
76
|
+
}
|
|
77
|
+
export declare function sendEmail(opts: SendEmailOptions): Promise<void>;
|
|
78
|
+
export declare function createDraft(opts: Omit<SendEmailOptions, 'saveToSentItems'>): Promise<Message>;
|
|
79
|
+
export declare function replyToMessage(id: string, body: string, replyAll?: boolean): Promise<void>;
|
|
80
|
+
export declare function forwardMessage(id: string, to: string[], comment?: string): Promise<void>;
|
|
81
|
+
export declare function markMessageRead(id: string, isRead?: boolean): Promise<void>;
|
|
82
|
+
export declare function flagMessage(id: string, status?: 'Flagged' | 'Complete' | 'NotFlagged'): Promise<void>;
|
|
83
|
+
export declare function moveMessage(id: string, destinationFolderId: string): Promise<Message>;
|
|
84
|
+
export declare function deleteMessage(id: string): Promise<void>;
|
|
85
|
+
export declare function searchMessages(query: string, top?: number): Promise<Message[]>;
|
|
86
|
+
export declare function listFolders(): Promise<MailFolder[]>;
|
|
87
|
+
export declare function getFolder(idOrName: string): Promise<MailFolder>;
|
|
88
|
+
export declare function getUnreadMessages(top?: number): Promise<Message[]>;
|
|
89
|
+
export declare function sendDraft(draftId: string): Promise<void>;
|
|
90
|
+
//# sourceMappingURL=mail.d.ts.map
|