Messaging connectors giving AI agents authenticated, normalized access to email and chat platforms
Project description
appif -- Application Interfaces
A Python library of messaging connectors that give AI agents authenticated, normalized access to email and chat platforms.
Purpose
Agents need information that lives behind logins: email threads, Slack messages, team conversations. This library provides a set of connectors that authenticate as you and return clean, structured MessageEvent objects suitable for agent reasoning -- platform-specific APIs are fully encapsulated behind a shared Connector protocol.
For the complete usage guide -- the unified model, per-connector mapping tables, code examples, and environment variable reference -- see docs/usage.md.
Quick Start
pip install appif
from appif.adapters.gmail import GmailConnector
from appif.domain.messaging.models import MessageEvent, MessageContent
class MyListener:
def on_message(self, event: MessageEvent) -> None:
# Every platform delivers the same MessageEvent:
# event.author.display_name -- who sent it
# event.content.text -- what they said
# event.conversation_ref -- opaque handle for reply
# event.metadata -- platform-specific extras
print(f"[{event.connector}] {event.author.display_name}: {event.content.text}")
connector = GmailConnector()
connector.connect()
connector.register_listener(MyListener())
# Reply to any received message:
# connector.send(event.conversation_ref, MessageContent(text="Got it."))
All three connectors (Gmail, Outlook, Slack) follow this same pattern. The full model, per-connector setup, and examples are in docs/usage.md.
Supported Connectors
| Service | Connector | Inbound Method | Status |
|---|---|---|---|
| Gmail | Google API (OAuth 2.0) | history.list polling |
Active |
| Outlook / Microsoft 365 | Microsoft Graph API | Delta-query polling | Active |
| Slack | Slack API (Bolt + Socket Mode) | Real-time Socket Mode | Active |
See docs/usage.md for how each platform maps to the unified model, setup instructions, and working code examples.
Installation
For development
uv venv .venv
source .venv/bin/activate
uv pip install -e ".[dev]"
As a library dependency
pip install appif
Prerequisites
- Python 3.13.x
- uv (for development)
Configuration
Credentials are stored in ~/.env and loaded at runtime:
cp .env.example ~/.env
| Variable | Service | Required |
|---|---|---|
APPIF_GMAIL_CLIENT_ID |
Gmail | Yes -- Google Cloud OAuth client ID |
APPIF_GMAIL_CLIENT_SECRET |
Gmail | Yes -- Google Cloud OAuth client secret |
APPIF_GMAIL_ACCOUNT |
Gmail | Yes -- Account email address |
APPIF_OUTLOOK_CLIENT_ID |
Outlook | Yes -- Azure AD app (client) ID |
APPIF_OUTLOOK_TENANT_ID |
Outlook | Optional -- Azure AD tenant (default: common) |
APPIF_SLACK_BOT_OAUTH_TOKEN |
Slack | Yes -- Bot user OAuth token (xoxb-...) |
APPIF_SLACK_BOT_APP_LEVEL_TOKEN |
Slack | Yes -- App-level token for Socket Mode (xapp-...) |
See .env.example for the full template with all optional variables.
Project Structure
application_interfaces/
├── src/
│ └── appif/ # Top-level package (PyPI: appif)
│ ├── __init__.py # Version via importlib.metadata
│ ├── domain/
│ │ └── messaging/ # Connector protocol, canonical models, errors
│ ├── adapters/
│ │ ├── gmail/ # Gmail messaging connector
│ │ ├── outlook/ # Outlook messaging connector
│ │ └── slack/ # Slack messaging connector
│ └── infrastructure/ # Credential loading
├── tests/
│ ├── unit/ # 241 unit tests
│ ├── integration/
│ └── e2e/
├── scripts/ # OAuth consent flows
├── docs/design/ # Design documents per adapter
├── pyproject.toml
├── ADAPTERS.md # Detailed adapter documentation
├── .env.example
└── readme.md
Development
# Set up dev environment
uv venv .venv
source .venv/bin/activate
uv pip install -e ".[dev]"
# Run all unit tests (241 tests)
pytest tests/unit -v
# Run adapter-specific tests
pytest tests/unit/test_gmail_*.py -v
pytest tests/unit/test_outlook_*.py -v
# Lint and format
ruff check src/ tests/
ruff format src/ tests/
# Type check
mypy src/
Architecture
Connector Protocol
All messaging connectors implement a shared Connector protocol (appif.domain.messaging.ports.Connector) -- a transport adapter that:
- Connects to an external system and manages authentication
- Emits normalized
MessageEventobjects to registered listeners - Delivers outbound messages via
send(target, content) - Supports historical backfill alongside realtime event ingestion
- Advertises capabilities so upstream logic branches on what the connector supports, not which platform it is
All connectors produce identical canonical types (MessageEvent, ConversationRef, SendReceipt). Platform-specific SDK code is fully encapsulated -- zero Slack/Outlook/Gmail types leak through the public interface.
Internal Module Pattern
Each adapter follows the same decomposition:
src/appif/adapters/<platform>/
├── __init__.py # Public exports
├── connector.py # Connector protocol implementation
├── _auth.py # Authentication (protocol + implementation)
├── _normalizer.py # Platform message -> MessageEvent
├── _message_builder.py # MessageContent -> platform request (email adapters)
├── _poller.py # Inbound message detection (email adapters)
└── _rate_limiter.py # Retry + platform error -> domain error mapping
Credential Setup
| Adapter | Consent Script | Setup Guide |
|---|---|---|
| Gmail | python scripts/gmail_consent.py <account> |
docs/design/gmail/setup.md |
| Outlook | python scripts/outlook_consent.py <account> |
docs/design/outlook/setup.md |
| Slack | N/A (tokens from Slack app) | docs/design/slack/setup.md |
License
MIT -- see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file appif-0.2.1.tar.gz.
File metadata
- Download URL: appif-0.2.1.tar.gz
- Upload date:
- Size: 139.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c4fa71eddd1aeddffdc4525a103cfb8906d3d59847d22914555c0a29e42f691
|
|
| MD5 |
cc7429321f1650274ea7128ec96b496e
|
|
| BLAKE2b-256 |
4a96464a9ff829a5595d49aba4821e5e00c33a9b423b74a651995e83f151f510
|
File details
Details for the file appif-0.2.1-py3-none-any.whl.
File metadata
- Download URL: appif-0.2.1-py3-none-any.whl
- Upload date:
- Size: 50.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ddda0464590840f6f183c4831695d8074cfead9d2d6911f3059856334b509b1b
|
|
| MD5 |
f1fe0a3ed7c79aacc30292d16ce91d8d
|
|
| BLAKE2b-256 |
6f0f920850fa158c425716e07920a9a16b163de8c10feae739266080a406d0f6
|