Python bindings for Apple's MailKit framework, enabling developers to create mail extensions that integrate with macOS Mail applications
—
Protocol definitions for creating Mail extensions including message decoders, encoders, security handlers, action handlers, and content blockers. This module defines the interfaces that Mail extensions must implement to provide custom functionality.
Base protocol for Mail extensions. All Mail extensions should conform to this protocol.
# Protocol: MEExtension
def handlerForMessageActions(self):
"""
Return a handler for message actions.
Returns:
Handler object conforming to MEMessageActionHandler protocol, or None
"""
def handlerForMessageSecurity(self):
"""
Return a handler for message security operations.
Returns:
Handler object conforming to MEMessageSecurityHandler protocol, or None
"""
def handlerForContentBlocker(self):
"""
Return a handler for content blocking.
Returns:
Handler object conforming to MEContentBlocker protocol, or None
"""
def handlerForComposeSession_(self, session):
"""
Return a handler for compose sessions.
Args:
session: MEComposeSession instance
Returns:
Handler object conforming to MEComposeSessionHandler protocol, or None
"""Protocol for decoding messages. Extensions implementing this protocol can provide custom message decoding functionality.
# Protocol: MEMessageDecoder
def decodedMessageForMessageData_(self, messageData):
"""
Decode message data and return a decoded message.
Args:
messageData: NSData containing the raw message data
Returns:
MEDecodedMessage: Decoded message object, or None if decoding failed
"""Protocol for encoding messages. Extensions implementing this protocol can provide custom message encoding functionality.
# Protocol: MEMessageEncoder
def getEncodingStatusForMessage_composeContext_completionHandler_(
self, message, composeContext, completionHandler
):
"""
Get encoding status for a message.
Args:
message: The message to get encoding status for
composeContext: MEComposeContext with compose information
completionHandler: Completion handler: (MEOutgoingMessageEncodingStatus) -> None
"""
def encodeMessage_composeContext_completionHandler_(
self, message, composeContext, completionHandler
):
"""
Encode a message for sending.
Args:
message: The message to encode
composeContext: MEComposeContext with compose information
completionHandler: Completion handler: (MEMessageEncodingResult) -> None
"""Protocol for handling message security operations. Extensions implementing this protocol can provide custom security functionality.
# Protocol: MEMessageSecurityHandler
def extensionViewControllerForMessageContext_(self, messageContext):
"""
Return a view controller for the message context.
Args:
messageContext: Context information for the message
Returns:
UIViewController: View controller for displaying security information
"""
def extensionViewControllerForMessageSigners_(self, messageSigners):
"""
Return a view controller for message signers.
Args:
messageSigners: List of MEMessageSigner objects
Returns:
UIViewController: View controller for displaying signer information
"""
def primaryActionClickedForMessageContext_completionHandler_(
self, messageContext, completionHandler
):
"""
Handle primary action click for a message.
Args:
messageContext: Context information for the message
completionHandler: Completion handler: (NSError or None) -> None
"""Protocol for handling message actions. Extensions implementing this protocol can provide custom message action functionality.
# Protocol: MEMessageActionHandler
def decideActionForMessage_completionHandler_(self, message, completionHandler):
"""
Decide what action to take for a message.
Args:
message: MEMessage object to make a decision about
completionHandler: Completion handler: (MEMessageActionDecision) -> None
"""Protocol for content blocking functionality. Extensions implementing this protocol can provide content filtering capabilities.
# Protocol: MEContentBlocker
def contentRulesJSON(self):
"""
Return JSON string containing content blocking rules.
Returns:
str: JSON string with content blocking rules in Safari Content Blocker format
"""Protocol for handling compose session events and operations. Extensions implementing this protocol can customize the compose experience.
# Protocol: MEComposeSessionHandler
def mailComposeSessionDidBegin_(self, session):
"""
Called when a compose session begins.
Args:
session: MEComposeSession that began
"""
def mailComposeSessionDidEnd_(self, session):
"""
Called when a compose session ends.
Args:
session: MEComposeSession that ended
"""
def viewControllerForSession_(self, session):
"""
Return a view controller for the compose session.
Args:
session: MEComposeSession instance
Returns:
UIViewController: View controller for the compose session
"""
def session_annotateAddressesWithCompletionHandler_(self, session, completionHandler):
"""
Annotate addresses in a compose session.
Args:
session: MEComposeSession instance
completionHandler: Completion handler: (List[MEAddressAnnotation]) -> None
"""
def session_canSendMessageWithCompletionHandler_(self, session, completionHandler):
"""
Check if a message can be sent in the session.
Args:
session: MEComposeSession instance
completionHandler: Completion handler: (NSError or None) -> None
"""
def additionalHeadersForSession_(self, session):
"""
Provide additional headers for the session.
Args:
session: MEComposeSession instance
Returns:
dict: Dictionary of additional headers, or None
"""
def requiredHeaders(self):
"""
Return required headers for compose sessions.
Returns:
List[str]: List of required header names, or None
"""import MailKit
from Foundation import NSObject
class CustomMessageDecoder(NSObject):
"""Custom message decoder implementation."""
def decodedMessageForMessageData_(self, messageData):
"""Decode custom message format."""
try:
# Decode the message data
# This is where you would implement your custom decoding logic
decoded_data = self.decode_custom_format(messageData)
# Create security information
security_info = MailKit.MEMessageSecurityInformation.alloc().initWithSigners_isEncrypted_signingError_encryptionError_(
signers=[],
isEncrypted=False,
signingError=None,
encryptionError=None
)
# Create decoded message
decoded_message = MailKit.MEDecodedMessage.alloc().initWithData_securityInformation_context_(
data=decoded_data,
securityInformation=security_info,
context=None
)
return decoded_message
except Exception as e:
print(f"Failed to decode message: {e}")
return None
def decode_custom_format(self, data):
"""Implement your custom decoding logic here."""
# Placeholder for custom decoding
return dataimport MailKit
from Foundation import NSObject
class CustomActionHandler(NSObject):
"""Custom message action handler implementation."""
def decideActionForMessage_completionHandler_(self, message, completionHandler):
"""Decide action based on message analysis."""
try:
# Analyze message to determine action
action_decision = self.analyze_message_for_action(message)
# Call completion handler with decision
completionHandler(action_decision)
except Exception as e:
print(f"Failed to decide action: {e}")
completionHandler(None)
def analyze_message_for_action(self, message):
"""Analyze message and return action decision."""
# Placeholder for message analysis logic
# Return appropriate MEMessageActionDecision
return Noneimport MailKit
from Foundation import NSObject
import json
class CustomContentBlocker(NSObject):
"""Custom content blocker implementation."""
def contentRulesJSON(self):
"""Return content blocking rules in JSON format."""
try:
# Define content blocking rules
rules = [
{
"trigger": {
"url-filter": ".*tracking.*",
"resource-type": ["image"]
},
"action": {
"type": "block"
}
},
{
"trigger": {
"url-filter": ".*analytics.*"
},
"action": {
"type": "block"
}
}
]
return json.dumps(rules)
except Exception as e:
print(f"Failed to generate content rules: {e}")
return "[]"import MailKit
from Foundation import NSObject
class CustomComposeSessionHandler(NSObject):
"""Custom compose session handler implementation."""
def mailComposeSessionDidBegin_(self, session):
"""Handle compose session beginning."""
print("Compose session began")
# Perform any initialization needed for the session
def mailComposeSessionDidEnd_(self, session):
"""Handle compose session ending."""
print("Compose session ended")
# Perform any cleanup needed
def viewControllerForSession_(self, session):
"""Return custom view controller for session."""
# Return a custom view controller if needed
return None
def session_annotateAddressesWithCompletionHandler_(self, session, completionHandler):
"""Annotate addresses in the session."""
try:
# Create address annotations
annotations = self.create_address_annotations(session)
completionHandler(annotations)
except Exception as e:
print(f"Failed to annotate addresses: {e}")
completionHandler([])
def session_canSendMessageWithCompletionHandler_(self, session, completionHandler):
"""Check if message can be sent."""
try:
# Validate message for sending
can_send = self.validate_message_for_sending(session)
if can_send:
completionHandler(None) # No error means can send
else:
# Create error for why message cannot be sent
error = self.create_validation_error()
completionHandler(error)
except Exception as e:
print(f"Failed to validate message: {e}")
completionHandler(e)
def additionalHeadersForSession_(self, session):
"""Provide additional headers."""
return {
"X-Custom-Extension": "CustomMailExtension",
"X-Version": "1.0"
}
def requiredHeaders(self):
"""Return required headers."""
return ["Subject", "To"]
def create_address_annotations(self, session):
"""Create address annotations for the session."""
# Placeholder for annotation creation logic
return []
def validate_message_for_sending(self, session):
"""Validate if message can be sent."""
# Placeholder for validation logic
return True
def create_validation_error(self):
"""Create validation error."""
# Placeholder for error creation
return Noneimport MailKit
from Foundation import NSObject
class CompleteMailExtension(NSObject):
"""Complete Mail extension implementing multiple protocols."""
def __init__(self):
super().__init__()
self.action_handler = CustomActionHandler.alloc().init()
self.security_handler = CustomSecurityHandler.alloc().init()
self.content_blocker = CustomContentBlocker.alloc().init()
# MEExtension protocol methods
def handlerForMessageActions(self):
"""Return message action handler."""
return self.action_handler
def handlerForMessageSecurity(self):
"""Return message security handler."""
return self.security_handler
def handlerForContentBlocker(self):
"""Return content blocker handler."""
return self.content_blocker
def handlerForComposeSession_(self, session):
"""Return compose session handler."""
return CustomComposeSessionHandler.alloc().init()
# Usage in extension main
# extension = CompleteMailExtension.alloc().init()Install with Tessl CLI
npx tessl i tessl/pypi-pyobjc-framework-mailkit