Metadata-Version: 2.4
Name: apigraph
Version: 0.1.0
Summary: Python SDK for Microsoft Graph API — Mail and SharePoint made simple
License: MIT License
        
        Copyright (c) 2026 batichico
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/batichico/apigraph
Project-URL: Documentation, https://github.com/batichico/apigraph#readme
Project-URL: Issues, https://github.com/batichico/apigraph/issues
Keywords: microsoft,graph,api,mail,sharepoint,sdk,azure
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28
Requires-Dist: msal>=1.20
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Dynamic: license-file

# apigraph

Python SDK for **Microsoft Graph API** — interact with Mail and SharePoint using a clean, simple interface.

## Features

- **Mail**: list folders & subfolders, fetch messages, read content, mark as read, move between folders, create folders.
- **SharePoint**: list drives, browse items, download files, move items.
- **Context manager** support (`with` statement handles connect/disconnect automatically).
- **Structured exceptions** (`HttpConnectionError`, `MailBoxException`) for predictable error handling.
- Certificate-based authentication via [MSAL](https://github.com/AzureAD/microsoft-authentication-library-for-python).

## Requirements

- Python ≥ 3.10
- An Azure AD **App Registration** with:
  - `Mail.Read`, `Mail.ReadWrite` (and/or `Sites.Read.All`, `Sites.ReadWrite.All` for SharePoint) **application permissions**.
  - A **certificate** uploaded to the App Registration.

## Installation

```bash
pip install apigraph
```

Or from source:

```bash
git clone https://github.com/YOUR_USERNAME/apigraph.git
cd apigraph
pip install -e .
```

## Configuration

Set the following environment variables (copy `.env.example` as a starting point):

| Variable | Description |
|---|---|
| `APIGRAPH_CLIENT_ID` | Azure App Registration client ID |
| `APIGRAPH_TENANT_ID` | Azure tenant ID |
| `APIGRAPH_CERT_PATH` | Path to the private key PEM file |
| `APIGRAPH_CERT_THUMBPRINT` | Certificate thumbprint (hex, no colons) |

```bash
cp .env.example .env
# edit .env with your values
```

## Quick start

```python
from apigraph import Graphapi

with Graphapi("user@company.com") as api:
    # List mail folders
    folders = api.fetch_mail_folders()
    for f in folders["value"]:
        print(f["displayName"], "—", f["id"])

    # Fetch unread emails
    mails = api.fetch_mails(filter_read_status="unread")
    for m in mails["value"]:
        print(m["subject"])

    # Get full content of an email
    content = api.get_mail_content(api.mailbox_email, mails["value"][0]["id"])

    # Mark as read
    api.mark_as_read(mails["value"][0]["id"])

    # Move email to a folder by name
    api.move_to_folder_by_name(mails["value"][0]["id"], "Archive")
```

### SharePoint example

```python
from apigraph import Graphapi

SITE_ID  = "your-site-id"
DRIVE_ID = "your-drive-id"

with Graphapi("user@company.com") as api:
    drives = api.list_sharepoint_drives(SITE_ID)
    folder_id = api.get_drive_folder_by_name(DRIVE_ID, "Reports")
    items = api.list_drive_items(DRIVE_ID, folder_id)
    for item in items:
        print(item["name"])
    content = api.download_drive_item(DRIVE_ID, items[0]["id"])
```

## API reference

| Method | Description |
|---|---|
| `fetch_mail_folders()` | List all mail folders |
| `fetch_mail_subfolders(folder_id)` | List subfolders of a folder |
| `fetch_all_folders_and_subfolders()` | Full folder tree with IDs |
| `fetch_mails(filter_read_status)` | Fetch messages (`None`/`"read"`/`"unread"`) |
| `fetch_mails_from_folder(mailbox, folder_id)` | Messages by folder ID |
| `fetch_mails_from_folder_by_name(folder_name)` | Messages by folder name |
| `mark_as_read(mail_id)` | Mark a message as read |
| `move_to_folder_by_name(email_id, folder_name)` | Move message by folder name |
| `move_to_folder_by_id(email_id, folder_id)` | Move message by folder ID |
| `create_folder(folder_name)` | Create a mail folder |
| `create_subfolder(parent_id, name)` | Create a subfolder |
| `get_mail_content(mailbox, email_id, filter_query)` | Retrieve message content |
| `get_mail_content_from_folder(folder, field, value)` | Find message by arbitrary field |
| `get_mail_by_subject(folder_name, subject_text)` | Find message by subject |
| `fetch_paginated(url)` | Generic paginated Graph request |
| `list_sharepoint_drives(site_id)` | List drives in a site |
| `list_sharepoint_drive_items(site_id, drive_id)` | Root items of a drive |
| `list_drive_items_by_path(site_id, drive_id, path)` | Items at a path |
| `list_drive_items(drive_id, folder_id)` | Items in a folder (paginated) |
| `download_drive_item(drive_id, item_id)` | Download file bytes |
| `get_drive_folder_by_name(drive_id, folder_name)` | Folder ID by name |
| `move_drive_item(drive_id, item_id, target_folder_id)` | Move a drive item |

## Error handling

```python
from apigraph import Graphapi, HttpConnectionError, MailBoxException

try:
    with Graphapi("user@company.com") as api:
        api.mark_as_read("bad-id")
except MailBoxException as e:
    print("Config error:", e.message, e.details)
except HttpConnectionError as e:
    print("HTTP error:", e.message, e.status_code, e.details)
```

## Development

```bash
pip install -e ".[dev]"
pytest tests/
ruff check src/
```

## License

[MIT](LICENSE)
