or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

assets.mdattachments.mdconfiguration.mdcore-notifications.mdindex.mdlocalization.mdplugin-system.mdstorage.md
tile.json

attachments.mddocs/

Attachment Handling

File attachment support for notifications including local files, URLs, and various attachment sources with size management and caching. AppriseAttachment provides comprehensive attachment handling for notifications across different file types and sources.

Capabilities

AppriseAttachment Class

Manages file attachments from multiple sources including local files, remote URLs, and data streams. Provides size management, caching, and format detection.

class AppriseAttachment:
    def __init__(self, paths=None, asset=None, cache=True, location=None):
        """
        Initialize attachment manager.
        
        Parameters:
        - paths (str|list, optional): File paths, URLs, or attachment objects
        - asset (AppriseAsset, optional): Asset configuration
        - cache (bool): Enable attachment caching
        - location (str, optional): Base location for relative paths
        """

    def add(self, attachments, asset=None, cache=None):
        """
        Add attachment(s) to the manager.
        
        Parameters:
        - attachments (str|list): File paths, URLs, or attachment objects
        - asset (AppriseAsset, optional): Asset configuration for attachments
        - cache (bool, optional): Override default caching behavior
        
        Returns:
        bool: True if at least one attachment was successfully added
        """

    def clear(self):
        """
        Remove all attachments from the manager.
        """

    def pop(self, index=-1):
        """
        Remove and return attachment by index.
        
        Parameters:
        - index (int): Index of attachment to remove (-1 for last)
        
        Returns:
        AttachBase: Removed attachment object
        """

    def size(self, mime_type=None):
        """
        Get total size of attachments.
        
        Parameters:
        - mime_type (str, optional): Filter by MIME type
        
        Returns:
        int: Total size in bytes of matching attachments
        """

    @staticmethod
    def instantiate(url, asset=None, cache=None):
        """
        Create attachment from URL or path.
        
        Parameters:
        - url (str): File path or URL to attachment
        - asset (AppriseAsset, optional): Asset configuration
        - cache (bool, optional): Enable caching for this attachment
        
        Returns:
        AttachBase: Attachment object or None if failed
        """

    def sync(self):
        """
        Synchronize all attachments and validate accessibility.
        
        Returns:
        bool: True if all attachments are accessible
        """

    @property
    def attachments(self):
        """
        List of attachment objects.
        
        Returns:
        list: AttachBase objects for all loaded attachments
        """

    @property
    def max_file_size(self):
        """
        Maximum allowed file size for attachments.
        
        Returns:
        int: Maximum file size in bytes
        """

AttachBase Class

Base class for attachment handlers supporting different attachment sources and types.

class AttachBase(URLBase):
    def download(self):
        """
        Download attachment content.
        
        Returns:
        bytes: Attachment content data
        """

    def exists(self):
        """
        Check if attachment exists and is accessible.
        
        Returns:
        bool: True if attachment exists
        """

    def invalidate(self):
        """
        Invalidate cached attachment content.
        """

    @property
    def name(self):
        """
        Attachment filename.
        
        Returns:
        str: Name of the attachment file
        """

    @property
    def path(self):
        """
        Attachment path or URL.
        
        Returns:
        str: Full path or URL to attachment
        """

    @property
    def mimetype(self):
        """
        MIME type of the attachment.
        
        Returns:
        str: MIME type (e.g., 'image/jpeg', 'application/pdf')
        """

    @property
    def size(self):
        """
        Size of the attachment.
        
        Returns:
        int: Size in bytes
        """

AttachmentManager Class

Singleton manager for attachment plugin discovery and loading.

class AttachmentManager:
    def load_modules(self, path=None, name=None):
        """
        Load attachment plugin modules.
        
        Parameters:
        - path (str, optional): Path to plugin directory
        - name (str, optional): Specific plugin name to load
        
        Returns:
        bool: True if modules were loaded successfully
        """

    def plugins(self):
        """
        Get available attachment plugins.
        
        Returns:
        dict: Available attachment plugin classes
        """

    def schemas(self):
        """
        Get supported attachment URL schemas.
        
        Returns:
        list: Supported URL schemas for attachments
        """

Supported Attachment Sources

Local Files

  • File system paths (absolute and relative)
  • Glob patterns for multiple files
  • Directory contents

Remote URLs

  • HTTP/HTTPS URLs
  • FTP URLs
  • Data URLs (data:// scheme)

Content Types

  • Images (JPEG, PNG, GIF, WebP, etc.)
  • Documents (PDF, DOC, TXT, etc.)
  • Archives (ZIP, TAR, etc.)
  • Any binary or text content

Usage Examples

Basic Attachment Usage

import apprise

# Create attachment from local file
attach = apprise.AppriseAttachment('/path/to/document.pdf')

# Create Apprise instance and send with attachment
apobj = apprise.Apprise()
apobj.add('mailto://user:pass@gmail.com')

apobj.notify(
    body='Please find the attached document',
    title='Document Delivery',
    attach=attach
)

Multiple Attachments

import apprise

# Add multiple attachments from different sources
attach = apprise.AppriseAttachment()

# Local files
attach.add('/path/to/report.pdf')
attach.add('/path/to/images/chart.png')

# Remote URL
attach.add('https://example.com/data.xlsx')

# Multiple files with glob pattern
attach.add('/path/to/logs/*.log')

print(f"Total attachments: {len(attach.attachments)}")
print(f"Total size: {attach.size()} bytes")

# Send notification with all attachments
apobj = apprise.Apprise()
apobj.add('slack://token/channel')
apobj.notify(
    body='Daily report with attachments',
    title='Daily Report',
    attach=attach
)

Attachment Management

import apprise

attach = apprise.AppriseAttachment()

# Add attachments with size checking
attach.add('/path/to/large-file.zip')

# Check total size before sending
max_size = 25 * 1024 * 1024  # 25MB limit
if attach.size() > max_size:
    print(f"Attachments too large: {attach.size()} bytes")
    # Remove largest attachment
    attach.pop()  # Remove last added
else:
    print(f"Attachments OK: {attach.size()} bytes")

# Filter by MIME type
image_size = attach.size(mime_type='image/*')
print(f"Image attachments: {image_size} bytes")

# List attachment details
for i, attachment in enumerate(attach.attachments):
    print(f"Attachment {i + 1}:")
    print(f"  Name: {attachment.name}")
    print(f"  Path: {attachment.path}")
    print(f"  Type: {attachment.mimetype}")
    print(f"  Size: {attachment.size} bytes")
    print(f"  Exists: {attachment.exists()}")

Attachment Caching

import apprise

# Create attachment manager with caching disabled
attach = apprise.AppriseAttachment(cache=False)

# Add remote attachment with caching enabled
attach.add(
    'https://example.com/report.pdf',
    cache=True  # Enable caching for this specific attachment
)

# Add local file (caching not applicable)
attach.add('/path/to/local-file.txt')

# Check if attachment content is cached
for attachment in attach.attachments:
    if hasattr(attachment, 'invalidate'):
        # Clear cache if needed
        attachment.invalidate()
        print(f"Cache cleared for {attachment.name}")

Dynamic Attachment Creation

import apprise
import tempfile
import os

# Create temporary file for attachment
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
    f.write('This is a dynamically created attachment\n')
    f.write('Generated at runtime for notification\n')
    temp_path = f.name

try:
    # Create attachment from temporary file
    attach = apprise.AppriseAttachment(temp_path)
    
    # Send notification
    apobj = apprise.Apprise()
    apobj.add('discord://webhook_id/webhook_token')
    
    success = apobj.notify(
        body='Dynamic attachment example',
        title='Runtime Generated Content',
        attach=attach
    )
    
    if success:
        print("Notification with dynamic attachment sent successfully")
    
finally:
    # Cleanup temporary file
    os.unlink(temp_path)

Attachment Validation and Error Handling

import apprise

try:
    attach = apprise.AppriseAttachment()
    
    # Add attachment with validation
    success = attach.add('/path/to/file.pdf')
    if not success:
        print("Failed to add attachment")
    
    # Validate all attachments exist
    for attachment in attach.attachments:
        if not attachment.exists():
            print(f"Warning: Attachment not found: {attachment.path}")
        else:
            print(f"Attachment OK: {attachment.name} ({attachment.size} bytes)")
    
    # Check size limits
    if attach.size() > attach.max_file_size:
        print(f"Attachments exceed size limit: {attach.size()} > {attach.max_file_size}")
        
        # Remove attachments until under limit
        while attach.size() > attach.max_file_size and attach.attachments:
            removed = attach.pop()
            print(f"Removed attachment: {removed.name}")

except apprise.AttachmentException as e:
    print(f"Attachment error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

Custom Attachment Handling

import apprise

# Create attachment manager with custom location
attach = apprise.AppriseAttachment(location='/base/path')

# Add relative path attachment (resolved relative to location)
attach.add('documents/report.pdf')  # Resolves to /base/path/documents/report.pdf

# Create attachment directly using instantiate method
pdf_attach = apprise.AppriseAttachment.instantiate('/path/to/document.pdf')
if pdf_attach:
    print(f"Created attachment: {pdf_attach.name}")
    print(f"MIME type: {pdf_attach.mimetype}")

# Add multiple attachment types
attachments = [
    '/path/to/image.jpg',           # Local image
    'https://example.com/data.csv', # Remote CSV
    '/path/to/archive.zip'          # Local archive
]

for att_path in attachments:
    att_obj = apprise.AppriseAttachment.instantiate(att_path)
    if att_obj:
        attach.add(att_obj)
        print(f"Added {att_obj.mimetype}: {att_obj.name}")

Integration with Notification Services

import apprise

# Different services support different attachment types
def send_with_appropriate_attachments():
    # Email services - support most file types
    email_attach = apprise.AppriseAttachment([
        '/path/to/document.pdf',
        '/path/to/spreadsheet.xlsx',
        '/path/to/image.png'
    ])
    
    apobj_email = apprise.Apprise()
    apobj_email.add('mailto://user:pass@gmail.com')
    apobj_email.notify(
        body='Email with various attachments',
        title='Multi-format Attachments',
        attach=email_attach
    )
    
    # Slack/Discord - typically support images and common formats
    image_attach = apprise.AppriseAttachment([
        '/path/to/chart.png',
        '/path/to/screenshot.jpg'
    ])
    
    apobj_slack = apprise.Apprise()
    apobj_slack.add('slack://token/channel')
    apobj_slack.notify(
        body='Image attachments for team',
        title='Visual Update',
        attach=image_attach
    )

send_with_appropriate_attachments()