Skip to content

[Discord Provider] Add support to embeds in Discord Webhook and Notifier #46838

@1cadumagalhaes

Description

@1cadumagalhaes

Description

I would like to be able to send more complex discord messages, not only text formatted.

We are limited when using only the content/message field. This is an example of a notification we use today
Image

And this is a message in a custom notifier for airbyte

Image

To create this, we could either create the option to use an embed for the users, and let them format it; or define a template and set the fields in the notifier/webhook. This isnt complicated to do, here is the builder for the airbyte notifier

def format_airbyte_data(airbyte_data):
    """Convert Airbyte data payload (for success/failure) into a Discord embed format."""
    data = airbyte_data.get('data', {})
    if not data:
        return None
        
    # Determine status color (green for success, red for failure)
    color = 0x00FF00 if data.get('success', False) else 0xFF0000
    
    # Create the main embed
    embed = {
        "title": f"Airbyte Sync: {data.get('connection', {}).get('name', 'Unknown')}",
        "color": color,
        "fields": [
            {
                "name": "Status",
                "value": "✅ Success" if data.get('success', False) else "❌ Failed",
                "inline": True
            },
            {
                "name": "Duration",
                "value": data.get('durationFormatted', 'Unknown'),
                "inline": True
            },
            {
                "name": "Records",
                "value": f"Emitted: {data.get('recordsEmitted', 0)}\nCommitted: {data.get('recordsCommitted', 0)}",
                "inline": True
            },
            {
                "name": "Data Volume",
                "value": f"Emitted: {data.get('bytesEmittedFormatted', '0 B')}\nCommitted: {data.get('bytesCommittedFormatted', '0 B')}",
                "inline": True
            },
            {
                "name": "Source",
                "value": data.get('source', {}).get('name', 'Unknown'),
                "inline": True
            },
            {
                "name": "Destination",
                "value": data.get('destination', {}).get('name', 'Unknown'),
                "inline": True
            }
        ],
        "footer": {
            "text": f"Workspace: {data.get('workspace', {}).get('name', 'Unknown')} | Job ID: {data.get('jobId', 'Unknown')}"
        },
        "timestamp": data.get('finishedAt', datetime.utcnow().isoformat())
    }
    # Add URLs as a separate non-inline field if they exist
    urls = []
    if data.get('connection', {}).get('url'):
        urls.append(f"[View Connection]({data['connection']['url']})")
    if data.get('source', {}).get('url'):
        urls.append(f"[View Source]({data['source']['url']})")
    if data.get('destination', {}).get('url'):
        urls.append(f"[View Destination]({data['destination']['url']})")
    
    if urls:
        embed["fields"].append({
            "name": "Links",
            "value": " | ".join(urls),
            "inline": False
        })
    
    return {
        "embeds": [embed]
    }

Honestly this is quite easy and I'll probably have a version of it when I get a few minutes to work on it

Use case/motivation

No response

Related issues

No response

Are you willing to submit a PR?

  • Yes I am willing to submit a PR!

Code of Conduct

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions