Skip to content

Lightweight SMTP & POP3 Proxy for Microsoft 365 Shared Mailboxes

License

Notifications You must be signed in to change notification settings

sh0rch/m365proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

48 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

SMTP & POP3 Proxy for Microsoft 365 Shared Mailboxes

PyPI version License: MIT GitHub Repo

Why This Project?

Many legacy systems, embedded devices, and applications:

  • ❌ Do not support OAuth2 for sending or receiving email
  • ❌ Cannot access Microsoft 365 endpoints directly due to network restrictions
  • ❌ Require SMTP/POP3 and basic username/password authentication

This proxy provides a secure bridge between those tools and Microsoft 365:

  • πŸ›‘οΈ Messages are relayed through a single authenticated Microsoft 365 account
  • πŸ” Only authorized clients (defined in config) can use the proxy
  • 🌍 Useful when you can't expose your own mail servers in SPF records
  • πŸ“₯ Enables retrieval of mail from shared mailboxes via POP3
  • πŸ’Έ With a single low-cost Exchange Online Kiosk license + free shared mailboxes, you can build a distributed, multi-sender notification system β€” without a full SMTP infrastructure

Ideal for:

  • Network monitoring software
  • Firewalls, routers, printers, IP cameras
  • IoT and industrial equipment
  • Legacy on-prem systems
  • Environments with no internet access or firewall egress rules

This tool helps consolidate notifications from many devices and subsystems under one tenant, while still keeping SPF/DKIM/DMARC compliant and not exposing internal systems.


✨ New Features (v2)

  • πŸ†• POP3 STARTTLS support β€” mail clients can now upgrade plaintext POP3 connections to TLS securely
  • πŸ†• SMTP SMTPS support (TLS from start) β€” SMTPS (port 465) is now supported in addition to STARTTLS (port 587 or custom)
  • πŸ†• POP3S support (TLS from start) β€” full support for POP3 over SSL/TLS (port 995)
  • πŸ” Simultaneous operation of all modes β€” you can now run:
    • SMTP (with STARTTLS)
    • SMTPS (SSL/TLS)
    • POP3 (with STARTTLS)
    • POP3S (SSL/TLS) …on different ports, either individually or together
  • πŸ›  Improved configuration parser:
    • Clearer validation of TLS, ports, logging paths, and mailbox entries
    • Prevents conflicts like smtp_port == smtps_port
    • Enhanced proxy URL formatting and diagnostics
  • 🀝 Better compatibility with popular clients and devices:
    • Thunderbird, Outlook, MFDs, embedded IoT mailers, etc.
  • βœ… Final release for this stage β€” future possibilities (IMAP, shared calendars, folders) may push the project into enterprise mail territory, which goes beyond the scope and potentially conflicts with Microsoft licensing β€” and that’s not a direction this project is taking.

Overview

This tool is designed for cases where you want to use real mail clients and devices (like scan-to-email from printers or backup software) with Microsoft 365 but want to avoid exposing user credentials or managing OAuth2 flows manually.

It provides local endpoints (SMTP and POP3) that forward requests securely via Microsoft Graph.

Features

  • βœ… Transparent mail sending via Microsoft Graph /sendMail
  • βœ… Works with shared mailboxes ("Send As")
  • βœ… Supports large attachments (up to 150MB via Graph API chunked upload)
  • βœ… POP3 receiving, with folder selection and message flags
  • βœ… Shared folder access for POP3 download (e.g. service@domain.com)
  • βœ… STARTTLS and SMTPS support
  • βœ… Multiple mailboxes with independent credentials
  • βœ… Authenticated and secure
  • βœ… Python-based and container-ready

πŸš€ Quick Start

pip install m365proxy

#Create a configuration file interactively
m365proxy configure

# First-time login to Microsoft 365 via Device Flow
m365proxy login

# Start the proxy (SMTP + POP3)
m365proxy

πŸ“¦ Offline Mode & Queue

When Microsoft 365 is unreachable:

  • βœ‰οΈ Messages are queued to disk
  • πŸ”„ Automatically retried in background (every 5 minutes)
  • 🧊 No data loss β€” even if the device is offline for hours

You can inspect the queue at:

ls ~/.m365proxy/queue/

πŸ“‘ Architecture

  Legacy Device (SMTP) ─────┐
                            β”œβ”€> SMTP Proxy ──> Graph API ──> Exchange Mailbox
  App / Printer / Camera β”€β”€β”˜

  POP3 Client <────────────── POP3 Proxy <─── Graph API (Shared Mail)

🐍 Installation

To install the proxy as a Python package:

pip install m365proxy

You can then run it via:

m365proxy

Or:

python -m m365proxy

Usage

python -m m365proxy [options]
python -m m365proxy [-config CONFIG] [command]

Simple SMTP and POP3 mail proxy to Microsoft 365 mailbox over HTTPS (using Microsoft Graph API).

Options

Option Description
-h, --help Show help message and exit
-config CONFIG Path to configuration file (default: <home_folder>/.m365proxy/config.json)
-token TOKEN Path to token file (default: <config_folder>/tokens.enc)
-log-file PATH Log file path (default: <config_folder>/m365.log)
-log-level LEVEL Logging level for file. One of DEBUG, INFO, WARNING, ERROR (default: INFO)
-bind ADDRESS Bind address for services (default: 127.0.0.1)
-smtp-port PORT SMTP listening port (default: 10025)
-pop3-port PORT POP3 listening port (optional, default: None)
-https-proxy URL HTTPS proxy URL (e.g. http://proxy.local:3128)
-no-ssl Disable SSL/TLS for SMTP and POP3
-debug Enable verbose output (CLI only)
-quiet Suppress all output except errors (CLI only)

Commands

Command Description
(none) Start SMTP/POP3 proxy server
init-config Create minimal default config.json
configure Run interactive configuration
login Start Microsoft device code login flow
check-token Check current token validity
show-token Show contents of decrypted token
check-config Show effective configuration
test Send a test email
hash Hash password for use in config.json

πŸ“Œ hash requires an argument: the plain password to be hashed.


Examples

# Start the proxy with default config
python -m m365proxy

# Generate default config file
python -m m365proxy init-config

# Configure interactively
python -m m365proxy configure

# Login via Microsoft device code flow
python -m m365proxy login

# Start the proxy on custom SMTP port and bind to all interfaces
python -m m365proxy -smtp-port 2525 -bind 0.0.0.0

# Run with custom config and token paths in quiet mode
python -m m365proxy -config ./myconfig.json -token /tmp/mytoken.enc -quiet

# Run with detailed logging
python -m m365proxy -config /tmp/myconfig.json -token /tmp/mytoken.enc -log-file /tmp/m365.log -log-level DEBUG

🐳 Docker

Here's how to run m365proxy in a container:

Dockerfile:

FROM python:3.11-slim
WORKDIR /app

# Install the proxy from PyPI
RUN pip install m365proxy

# Copy configuration files
COPY config.json .
COPY tokens.enc .

# Expose required ports
EXPOSE 10025 10110

CMD ["m365proxy"]

Run example:

docker run -d \
  -v $(pwd)/config.json:/app/config.json \
  -v $(pwd)/tokens.enc:/app/tokens.enc \
  -p 10025:10025 -p 10110:10110 \
  m365proxy

πŸ›  You can also override config or token paths with -config and -token arguments.

πŸͺŸ Windows Task Scheduler

To auto-start the proxy on Windows:

  1. Open Task Scheduler
  2. Choose Create Basic Task
  3. Trigger: At startup or Log on
  4. Action: Start a program
  5. Set Program/script: to:
    pythonw
    
    Set Add arguments: to:
    -m m365proxy -quiet
    

🐧 systemd (Linux Autostart)

To run the proxy as a background service on Linux, create a systemd unit file:

/etc/systemd/system/m365proxy.service

[Unit]
Description=Microsoft 365 Mail Proxy
After=network.target

[Service]
ExecStart=/usr/bin/python3 -m m365proxy -quiet
WorkingDirectory=/opt/m365proxy
Restart=always
User=nobody
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target

Then enable and start:

sudo systemctl daemon-reload
sudo systemctl enable m365proxy
sudo systemctl start m365proxy

Sample Configuration (config.json)

{
  "user": "licensed@example.com",
  "client_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "tenant_id": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
  "allowed_domains": ["example.com"],
  "mailboxes": [
    {
      "username": "shared1@example.com",
      "password": "hashed-secret1"
    },
    {
      "username": "shared2@example.com",
      "password": "hashed-secret2"
    }
  ],
  "bind": "127.0.0.1",
  "smtp_port": 10025,
  "pop3_port": 10110,
  "https_proxy": {
    "url": "http://proxy.local:3128",
    "user": "proxyuser",
    "password": "proxypass"
  },
  "logging": {
    "level": "INFO"
  }
}

πŸ” All passwords hashed and stored locally.


Azure AD / Entra ID Setup

To use Microsoft Graph API, you must register your application in Microsoft Entra ID (Azure Active Directory).

1. Register Your App

  • Go to https://entra.microsoft.com
  • Navigate to Azure Active Directory β†’ App registrations β†’ New registration
  • Set a name like smtp-proxy, leave redirect URI empty (device code flow doesn't require it)

2. Save Credentials

  • Copy the Client ID and Tenant ID into your config.json

3. Configure Permissions

  • Go to API permissions β†’ Add a permission β†’ Microsoft Graph β†’ Delegated
  • Add:
    • Mail.Send (required, for outgoing mail)
    • Mail.Send.Shared (required, for outgoing mail)
    • Mail.ReadWrite (optional, for incoming mail)
    • Mail.ReadWrite.Shared (optional, for incoming mail)
    • offline_access (required, for refresh tokens)
  • Grant admin consent for your tenant

4. Enable Public Client Flow

  • Go to Authentication β†’ Enable public client (mobile & desktop)
  • Allow device code flow

5. Authorize the Proxy

  • Run the proxy with login
  • You will be prompted to sign in once in a browser
  • After that, tokens will be refreshed automatically

Shared Mailbox Configuration

To send or receive mail on behalf of shared addresses:

  • Go to Microsoft 365 Admin Center β†’ Shared mailboxes β†’ Create
  • Assign Send As or Send on Behalf rights to your user in the config

Grant Send As Rights (PowerShell):

Add-RecipientPermission -Identity shared@domain.com -Trustee user@domain.com -AccessRights SendAs

Grant Send on Behalf:

Set-Mailbox shared@domain.com -GrantSendOnBehalfTo user@domain.com

πŸ“Œ Send As is preferred for compatibility.

Shared mailboxes do not require licenses and can be used for routing, monitoring, and distribution identities.


Additional Permissions for POP3 Access

To read or delete messages from shared mailboxes using the POP3 proxy, you must add the following delegated Microsoft Graph API permissions to your app:

  • Mail.ReadWrite
  • Mail.ReadWrite.Shared

These permissions allow the proxy to fetch and delete messages on behalf of the user or shared mailbox.

πŸ›‘οΈ Without Mail.ReadWrite the proxy will not be able to mark or delete messages after downloading, which may result in repeated deliveries.

βœ… Admin consent is required for these permissions.


Disabling POP3 (Optional)

If your use case does not require access to incoming mail, you can disable POP3 entirely:

{
  "pop3_port": null
}

πŸ”• This prevents the proxy from exposing any POP3 service.


Notes

  • All outgoing messages use the address specified in MAIL FROM:.
  • The proxy preserves full message structure: subject, HTML, attachments.
  • Attachments are limited to 80MB by default (adjustable).
  • All allowed users are declared in mailboxes[].
  • SMTP/POP3 clients must authenticate using one of the defined username/password combinations.
  • POP3 supports UIDL to avoid downloading duplicates.

License

MIT β€” Author: sh0rch

About

Lightweight SMTP & POP3 Proxy for Microsoft 365 Shared Mailboxes

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages