CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyobjc-framework-mailkit

Python bindings for Apple's MailKit framework, enabling developers to create mail extensions that integrate with macOS Mail applications

Pending
Overview
Eval results
Files

extension-management.mddocs/

Extension Management

Extension manager for controlling Mail extensions, reloading content blockers, and managing visible messages. This module provides the core functionality for managing Mail extension lifecycle and operations.

Capabilities

MEExtensionManager

Manager for Mail extension operations and reloading. This is the primary class for controlling extension behavior and triggering system updates.

class MEExtensionManager:
    def reloadContentBlockerWithIdentifier_completionHandler_(
        self,
        identifier: str,  # Content blocker identifier
        completionHandler  # Completion handler: (NSError or None) -> None
    ):
        """
        Reload a content blocker with the specified identifier.
        
        Args:
            identifier: The unique identifier of the content blocker to reload
            completionHandler: Completion handler called when reload completes,
                             receives an NSError if the operation failed, None on success
        """
    
    def reloadVisibleMessagesWithCompletionHandler_(
        self,
        completionHandler  # Completion handler: (NSError or None) -> None
    ):
        """
        Reload all visible messages in the Mail application.
        
        Args:
            completionHandler: Completion handler called when reload completes,
                             receives an NSError if the operation failed, None on success
        """

MEExtensionViewController

Base view controller class for Mail extensions. Provides the foundation for creating custom view controllers in Mail extensions.

class MEExtensionViewController:
    """
    Base view controller for Mail extensions.
    
    This class provides the foundation for creating custom view controllers
    that integrate with the Mail application interface.
    
    Note: This class cannot be instantiated directly using init() or new().
    Subclass this class to create custom extension view controllers.
    """

Usage Examples

Reloading Content Blockers

import MailKit

# Reload a specific content blocker
def reload_content_blocker(extension_manager, blocker_id):
    """Reload a content blocker and handle the result."""
    
    def completion_handler(error):
        if error is None:
            print(f"Successfully reloaded content blocker: {blocker_id}")
        else:
            print(f"Failed to reload content blocker {blocker_id}: {error}")
    
    extension_manager.reloadContentBlockerWithIdentifier_completionHandler_(
        identifier=blocker_id,
        completionHandler=completion_handler
    )

# Example usage
# extension_manager would be provided by the Mail framework
# reload_content_blocker(extension_manager, "com.example.mailblocker")

Reloading Visible Messages

import MailKit

# Reload all visible messages
def reload_visible_messages(extension_manager):
    """Reload all visible messages and handle the result."""
    
    def completion_handler(error):
        if error is None:
            print("Successfully reloaded visible messages")
        else:
            print(f"Failed to reload visible messages: {error}")
    
    extension_manager.reloadVisibleMessagesWithCompletionHandler_(
        completionHandler=completion_handler
    )

# Example usage  
# extension_manager would be provided by the Mail framework
# reload_visible_messages(extension_manager)

Extension Manager Utility Class

import MailKit

class MailExtensionManager:
    """Utility class for managing Mail extension operations."""
    
    def __init__(self, extension_manager):
        """
        Initialize with a MEExtensionManager instance.
        
        Args:
            extension_manager: MEExtensionManager instance from the Mail framework
        """
        self.extension_manager = extension_manager
        self.reload_callbacks = {}
    
    def reload_content_blocker_async(self, blocker_id, callback=None):
        """
        Asynchronously reload a content blocker.
        
        Args:
            blocker_id: Identifier of the content blocker
            callback: Optional callback function to call on completion
        """
        def completion_handler(error):
            success = error is None
            if callback:
                callback(blocker_id, success, error)
            
            # Store result for later retrieval
            self.reload_callbacks[blocker_id] = {
                "success": success,
                "error": error,
                "timestamp": __import__("time").time()
            }
        
        self.extension_manager.reloadContentBlockerWithIdentifier_completionHandler_(
            identifier=blocker_id,
            completionHandler=completion_handler
        )
    
    def reload_visible_messages_async(self, callback=None):
        """
        Asynchronously reload visible messages.
        
        Args:
            callback: Optional callback function to call on completion
        """
        def completion_handler(error):
            success = error is None
            if callback:
                callback(success, error)
        
        self.extension_manager.reloadVisibleMessagesWithCompletionHandler_(
            completionHandler=completion_handler
        )
    
    def get_last_reload_result(self, blocker_id):
        """
        Get the result of the last reload operation for a content blocker.
        
        Args:
            blocker_id: Identifier of the content blocker
            
        Returns:
            dict: Result information or None if no reload has been performed
        """
        return self.reload_callbacks.get(blocker_id)

# Example usage
# manager = MailExtensionManager(extension_manager_instance)
# 
# def reload_callback(blocker_id, success, error):
#     if success:
#         print(f"Content blocker {blocker_id} reloaded successfully")
#     else:
#         print(f"Failed to reload content blocker {blocker_id}: {error}")
# 
# manager.reload_content_blocker_async("com.example.blocker", reload_callback)

Batch Content Blocker Operations

import MailKit

class BatchExtensionManager:
    """Manager for batch extension operations."""
    
    def __init__(self, extension_manager):
        self.extension_manager = extension_manager
        self.pending_operations = {}
    
    def reload_multiple_content_blockers(self, blocker_ids, completion_callback=None):
        """
        Reload multiple content blockers and track completion.
        
        Args:
            blocker_ids: List of content blocker identifiers
            completion_callback: Called when all operations complete
        """
        batch_id = f"batch_{__import__('time').time()}"
        self.pending_operations[batch_id] = {
            "total": len(blocker_ids),
            "completed": 0,
            "results": {},
            "callback": completion_callback
        }
        
        def individual_completion(blocker_id, error):
            batch_info = self.pending_operations[batch_id]
            batch_info["completed"] += 1
            batch_info["results"][blocker_id] = {
                "success": error is None,
                "error": error
            }
            
            # Check if batch is complete
            if batch_info["completed"] == batch_info["total"]:
                if batch_info["callback"]:
                    batch_info["callback"](batch_id, batch_info["results"])
                # Clean up
                del self.pending_operations[batch_id]
        
        # Start all reload operations
        for blocker_id in blocker_ids:
            self.extension_manager.reloadContentBlockerWithIdentifier_completionHandler_(
                identifier=blocker_id,
                completionHandler=lambda error, bid=blocker_id: individual_completion(bid, error)
            )
        
        return batch_id
    
    def get_batch_status(self, batch_id):
        """
        Get the status of a batch operation.
        
        Args:
            batch_id: Batch operation identifier
            
        Returns:
            dict: Batch status information or None if not found
        """
        return self.pending_operations.get(batch_id)

# Example usage
# batch_manager = BatchExtensionManager(extension_manager_instance)
# 
# def batch_completion(batch_id, results):
#     print(f"Batch {batch_id} completed:")
#     for blocker_id, result in results.items():
#         status = "SUCCESS" if result["success"] else "FAILED"
#         print(f"  {blocker_id}: {status}")
# 
# blocker_list = ["com.example.blocker1", "com.example.blocker2", "com.example.blocker3"]
# batch_id = batch_manager.reload_multiple_content_blockers(blocker_list, batch_completion)

Error Handling and Retry Logic

import MailKit
import time

class RobustExtensionManager:
    """Extension manager with retry logic and error handling."""
    
    def __init__(self, extension_manager, max_retries=3, retry_delay=1.0):
        self.extension_manager = extension_manager
        self.max_retries = max_retries
        self.retry_delay = retry_delay
        self.retry_attempts = {}
    
    def reload_content_blocker_with_retry(self, blocker_id, final_callback=None):
        """
        Reload content blocker with automatic retry on failure.
        
        Args:
            blocker_id: Content blocker identifier
            final_callback: Callback called after all retries exhausted
        """
        attempt_key = f"{blocker_id}_{time.time()}"
        self.retry_attempts[attempt_key] = 0
        
        def attempt_reload():
            attempt_count = self.retry_attempts[attempt_key]
            
            def completion_handler(error):
                if error is None:
                    # Success - clean up and notify
                    if attempt_key in self.retry_attempts:
                        del self.retry_attempts[attempt_key]
                    if final_callback:
                        final_callback(blocker_id, True, None, attempt_count + 1)
                else:
                    # Failure - check if we should retry
                    self.retry_attempts[attempt_key] += 1
                    current_attempt = self.retry_attempts[attempt_key]
                    
                    if current_attempt < self.max_retries:
                        print(f"Retrying content blocker reload {blocker_id} (attempt {current_attempt + 1}/{self.max_retries})")
                        # Schedule retry after delay
                        __import__("threading").Timer(self.retry_delay, attempt_reload).start()
                    else:
                        # All retries exhausted
                        if attempt_key in self.retry_attempts:
                            del self.retry_attempts[attempt_key]
                        if final_callback:
                            final_callback(blocker_id, False, error, current_attempt)
            
            self.extension_manager.reloadContentBlockerWithIdentifier_completionHandler_(
                identifier=blocker_id,
                completionHandler=completion_handler
            )
        
        # Start first attempt
        attempt_reload()

# Example usage
# robust_manager = RobustExtensionManager(extension_manager_instance, max_retries=3, retry_delay=2.0)
# 
# def final_callback(blocker_id, success, error, attempts):
#     if success:
#         print(f"Content blocker {blocker_id} reloaded successfully after {attempts} attempts")
#     else:
#         print(f"Failed to reload content blocker {blocker_id} after {attempts} attempts: {error}")
# 
# robust_manager.reload_content_blocker_with_retry("com.example.blocker", final_callback)

Install with Tessl CLI

npx tessl i tessl/pypi-pyobjc-framework-mailkit

docs

compose-sessions.md

extension-management.md

index.md

message-actions.md

message-classes.md

protocols-handlers.md

security-encryption.md

tile.json