← Back to Research

Overview

Single standard protocol for email, SMS, WhatsApp, Signal, and all messaging - true communication interoperability.

🎯 This is what msgs.global is already becoming!

Problem Statement

Communication is fragmented: - Email (SMTP/IMAP) - SMS (carrier-specific APIs, Telnyx, Twilio) - WhatsApp (proprietary API) - Signal (separate protocol) - Slack, Teams, Discord, etc.

Each requires: - Different protocols - Separate clients - Isolated conversations - No cross-platform search - Multiple notification streams

Vision

Universal Message Protocol (UMP)

Single API/Protocol that supports:
✅ Text messages (SMS, email, chat)
✅ Rich media (images, video, files)
✅ Real-time delivery (chat) and async (email)
✅ End-to-end encryption
✅ Read receipts, typing indicators
✅ Groups and channels
✅ Threads and conversations
✅ Voice and video calls

One inbox, one search, one unified experience

Current msgs.global Integration

You're already integrating: - Email (SMTP, IMAP, Postfix, Dovecot) - SMS (Telnyx webhooks: app/sms_webhooks.py) - WhatsApp (Telnyx/Twilio webhooks: app/whatsapp_webhooks.py) - Signal (Docker: docker-compose.signal.yml, webhooks: app/signal_webhooks.py)

Challenge: Each uses different APIs, storage, and presentation

Unified Protocol Design

1. Core Message Format

{
  "id": "ump:msg:abc123",
  "protocol_version": "1.0",
  "type": "message",
  "channel": "sms|email|whatsapp|signal|custom",
  "from": {
    "id": "ump:user:alice123",
    "display_name": "Alice Smith",
    "identifiers": {
      "email": "alice@msgs.global",
      "phone": "+15551234567",
      "whatsapp": "+15551234567",
      "signal": "+15551234567",
      "did": "did:msgs:alice123"
    }
  },
  "to": [
    {
      "id": "ump:user:bob456",
      "display_name": "Bob Jones",
      "identifiers": {...}
    }
  ],
  "conversation_id": "ump:conv:xyz789",
  "timestamp": "2026-03-07T20:00:00Z",
  "content": {
    "type": "text|rich|media",
    "text": "Hello from unified protocol!",
    "html": "<p>Hello from <b>unified</b> protocol!</p>",
    "attachments": [
      {
        "type": "image/jpeg",
        "url": "https://msgs.global/attachments/abc.jpg",
        "size": 524288,
        "hash": "sha256:..."
      }
    ]
  },
  "metadata": {
    "priority": "normal",
    "encryption": "e2ee",
    "read_receipt_requested": true,
    "expires_at": "2026-03-08T00:00:00Z"
  },
  "delivery_status": {
    "sent": "2026-03-07T20:00:00Z",
    "delivered": "2026-03-07T20:00:05Z",
    "read": "2026-03-07T20:01:00Z"
  }
}

2. Unified API

class UnifiedMessageAPI:
    """Single API for all messaging channels"""

    def send_message(self, message):
        """Send message via any channel"""
        # 1. Determine best channel for recipient
        channel = self.select_channel(message.to)

        # 2. Transform to channel-specific format
        if channel == 'email':
            return self.send_via_smtp(message)
        elif channel == 'sms':
            return self.send_via_telnyx_sms(message)
        elif channel == 'whatsapp':
            return self.send_via_telnyx_whatsapp(message)
        elif channel == 'signal':
            return self.send_via_signal(message)

    def receive_message(self, channel, raw_message):
        """Receive message from any channel and normalize"""
        # 1. Parse channel-specific format
        if channel == 'email':
            message = self.parse_smtp_message(raw_message)
        elif channel == 'sms':
            message = self.parse_telnyx_sms(raw_message)
        elif channel == 'whatsapp':
            message = self.parse_whatsapp(raw_message)
        elif channel == 'signal':
            message = self.parse_signal(raw_message)

        # 2. Convert to unified format
        unified_message = self.normalize_message(message, channel)

        # 3. Store in unified inbox
        self.store_message(unified_message)

        return unified_message

    def select_channel(self, recipient):
        """Intelligently select best channel for recipient"""
        # Check recipient preferences
        prefs = self.get_recipient_preferences(recipient)

        # Factors:
        # - Recipient's preferred channel
        # - Message urgency (SMS for urgent, email for formal)
        # - Content type (rich media -> WhatsApp, simple text -> SMS)
        # - Online status (real-time chat if online, email if offline)
        # - Cost (SMS premium, email free)

        if prefs.get('urgent') and recipient.has_sms:
            return 'sms'
        elif recipient.has_signal and prefs.get('encrypted'):
            return 'signal'
        elif recipient.has_whatsapp and message.has_media:
            return 'whatsapp'
        else:
            return 'email'  # Default fallback

3. Unified Storage

-- Single messages table for all channels
CREATE TABLE unified_messages (
    id VARCHAR(64) PRIMARY KEY,
    conversation_id VARCHAR(64),
    channel VARCHAR(20), -- sms, email, whatsapp, signal
    from_user_id INTEGER REFERENCES users(id),
    from_identifier JSONB, -- {email, phone, etc.}
    to_users JSONB[], -- Array of recipient identifiers
    content JSONB, -- Unified message content
    metadata JSONB,
    delivery_status JSONB,
    created_at TIMESTAMP DEFAULT NOW(),

    -- Channel-specific fields (optional)
    email_message_id VARCHAR(255),
    sms_message_id VARCHAR(100),
    whatsapp_message_id VARCHAR(100),
    signal_message_id VARCHAR(100)
);

-- Unified conversations (threads)
CREATE TABLE unified_conversations (
    id VARCHAR(64) PRIMARY KEY,
    participants JSONB[], -- Array of user identifiers
    subject TEXT, -- Email-style subject (optional for SMS/chat)
    channel VARCHAR(20), -- Primary channel
    created_at TIMESTAMP DEFAULT NOW(),
    last_message_at TIMESTAMP,
    message_count INTEGER DEFAULT 0
);

-- User identifiers (link all user's contact methods)
CREATE TABLE user_identifiers (
    user_id INTEGER REFERENCES users(id),
    identifier_type VARCHAR(20), -- email, phone, whatsapp, signal, did
    identifier_value VARCHAR(255),
    verified BOOLEAN DEFAULT FALSE,
    primary_for_channel BOOLEAN DEFAULT FALSE,
    UNIQUE(identifier_type, identifier_value)
);

CREATE INDEX idx_messages_conversation ON unified_messages(conversation_id);
CREATE INDEX idx_messages_user ON unified_messages(from_user_id);
CREATE INDEX idx_identifiers_user ON user_identifiers(user_id);

4. Integration Layer

File: app/unified_messaging.py

from flask import Blueprint, request, jsonify
from app.models import db, UnifiedMessage, UnifiedConversation
from app.sms_webhooks import send_telnyx_sms
from app.whatsapp_webhooks import send_whatsapp_message
from app.signal_webhooks import send_signal_message

unified_bp = Blueprint('unified', __name__)

@unified_bp.route('/api/v1/unified/send', methods=['POST'])
def send_unified_message():
    """Send message via any channel"""
    data = request.json

    # 1. Resolve recipient (find best identifier)
    recipient = resolve_recipient(data['to'])

    # 2. Select channel
    channel = select_best_channel(recipient, data)

    # 3. Create unified message
    message = UnifiedMessage(
        conversation_id=data.get('conversation_id', generate_conversation_id()),
        channel=channel,
        from_user_id=request.current_user.id,
        content=data['content']
    )

    # 4. Send via selected channel
    if channel == 'sms':
        result = send_telnyx_sms(
            to=recipient.phone,
            message=data['content']['text']
        )
        message.sms_message_id = result['message_id']

    elif channel == 'whatsapp':
        result = send_whatsapp_message(
            to=recipient.whatsapp,
            message=data['content']
        )
        message.whatsapp_message_id = result['message_id']

    elif channel == 'signal':
        result = send_signal_message(
            to=recipient.signal,
            message=data['content']['text']
        )
        message.signal_message_id = result['message_id']

    elif channel == 'email':
        result = send_smtp_message(
            to=recipient.email,
            subject=data.get('subject', '(no subject)'),
            body=data['content']['text']
        )
        message.email_message_id = result['message_id']

    # 5. Store message
    db.session.add(message)
    db.session.commit()

    return jsonify(message.to_dict()), 201

@unified_bp.route('/api/v1/unified/inbox')
def get_unified_inbox():
    """Get messages from all channels in one inbox"""
    user = request.current_user

    # Get all user's identifiers
    identifiers = UserIdentifier.query.filter_by(user_id=user.id).all()

    # Query messages across all channels
    messages = UnifiedMessage.query.filter(
        or_(*[
            UnifiedMessage.to_users.contains([{
                'type': ident.identifier_type,
                'value': ident.identifier_value
            }])
            for ident in identifiers
        ])
    ).order_by(UnifiedMessage.created_at.desc()).limit(100).all()

    return jsonify([msg.to_dict() for msg in messages])

@unified_bp.route('/api/v1/unified/conversations')
def get_conversations():
    """Get all conversations across channels"""
    user = request.current_user

    conversations = UnifiedConversation.query.filter(
        UnifiedConversation.participants.contains([{
            'user_id': user.id
        }])
    ).order_by(UnifiedConversation.last_message_at.desc()).all()

    return jsonify([
        {
            'id': conv.id,
            'subject': conv.subject,
            'participants': conv.participants,
            'channel': conv.channel,
            'last_message': conv.last_message_at,
            'message_count': conv.message_count,
            'unread_count': get_unread_count(conv.id, user.id)
        }
        for conv in conversations
    ])

# Webhook handlers (convert to unified format)

@unified_bp.route('/webhooks/sms/telnyx', methods=['POST'])
def telnyx_sms_webhook():
    """Receive SMS and store as unified message"""
    data = request.json

    message = UnifiedMessage(
        channel='sms',
        from_identifier={'phone': data['from']},
        to_users=[{'phone': data['to']}],
        content={'text': data['text']},
        sms_message_id=data['message_id']
    )

    db.session.add(message)
    db.session.commit()

    return '', 200

# Similar webhooks for WhatsApp, Signal, Email...

Webmail Integration

Unified Inbox UI

// Webmail: Single inbox showing all channels
function renderUnifiedInbox(messages) {
    messages.forEach(msg => {
        const channelIcon = {
            'email': '📧',
            'sms': '💬',
            'whatsapp': '💚',
            'signal': '🔒'
        }[msg.channel];

        renderMessage({
            icon: channelIcon,
            from: msg.from.display_name,
            subject: msg.content.text.substring(0, 50),
            timestamp: msg.timestamp,
            channel: msg.channel
        });
    });
}

// Smart compose: Auto-select channel
function composeMessage(recipient) {
    // Show available channels for recipient
    const availableChannels = getRecipientChannels(recipient);

    // Suggest best channel
    const suggested = suggestChannel(recipient, messageType);

    showComposer({
        to: recipient,
        channels: availableChannels,
        suggested: suggested
    });
}

Channel Routing Logic

Intelligent Channel Selection

def select_best_channel(recipient, message):
    """AI-powered channel selection"""

    # Factors to consider:
    factors = {
        'urgency': message.get('priority') == 'urgent',
        'has_media': len(message.get('attachments', [])) > 0,
        'formal': is_formal_content(message['content']),
        'encrypted_required': message.get('encryption') == 'required',
        'cost_sensitive': sender_preferences.get('minimize_cost'),
        'recipient_online': is_recipient_online(recipient)
    }

    # Decision tree
    if factors['encrypted_required']:
        if recipient.has_signal:
            return 'signal'
        elif recipient.has_whatsapp:
            return 'whatsapp'
        else:
            return 'email'  # With PGP

    if factors['urgency']:
        if recipient.has_sms:
            return 'sms'
        elif recipient.has_whatsapp and factors['recipient_online']:
            return 'whatsapp'
        else:
            return 'email'  # With high priority flag

    if factors['has_media']:
        if recipient.has_whatsapp:
            return 'whatsapp'
        else:
            return 'email'

    if factors['formal']:
        return 'email'

    # Default: Use recipient's preferred channel
    return recipient.preferred_channel or 'email'

Advantages for msgs.global

Current State

  • 4 separate systems (email, SMS, WhatsApp, Signal)
  • 4 different APIs
  • 4 storage schemas
  • Complex user experience

With Unified Protocol

  • ✅ Single API for developers
  • ✅ One search across all messages
  • ✅ Unified conversations (email thread + SMS replies)
  • ✅ Automatic channel failover
  • ✅ Cost optimization (route via cheapest available)
  • ✅ Better user experience

Migration Path

Phase 1: Unified Storage (Current → 3 months)

  • [x] Already have separate tables (messages, sms_messages, etc.)
  • [ ] Create unified_messages table
  • [ ] Migrate existing messages to unified format
  • [ ] Create user_identifiers linking table

Phase 2: Unified API (3-6 months)

  • [ ] Build unified send/receive API
  • [ ] Wrap existing channel APIs
  • [ ] Implement channel selection logic
  • [ ] Update webhooks to normalize to unified format

Phase 3: Webmail Integration (6-9 months)

  • [ ] Unified inbox view
  • [ ] Cross-channel search
  • [ ] Smart compose (channel selection)
  • [ ] Conversation threading across channels

Phase 4: Advanced Features (9-12 months)

  • [ ] AI-powered channel selection
  • [ ] Cross-channel read receipts
  • [ ] Unified notifications
  • [ ] Cost analytics and optimization

Protocol Specification

Standard compliance

  • Email: RFC 5322, SMTP, IMAP
  • SMS: Telnyx/Twilio APIs (industry standard)
  • WhatsApp: WhatsApp Business API
  • Signal: Signal Protocol (double ratchet)

Unified extensions

  • UMP-Header: Metadata for cross-channel messages
  • UMP-Conversation-ID: Thread messages across channels
  • UMP-Channel-Preference: Recipient's preferred channel

Status

🚀 ALREADY IN PROGRESS (msgs.global has all the pieces!)

Immediate Next Steps

  1. [ ] Design unified message schema
  2. [ ] Create migration from existing tables
  3. [ ] Build unified API wrapper
  4. [ ] Update webmail to show all channels
  5. [ ] Implement intelligent channel routing
  6. [ ] Cross-channel conversation threading

This is your competitive differentiator! No other platform unifies email, SMS, WhatsApp, and Signal like this.