Mail plug-ins will stop working in a future macOS release
New MailKit framework, macOS 12.0+
Mail extensions are built on the same underlying foundation as other app extensions, like Safari app extensions and share sheet extensions
can be distributed standalone, bundled in an app (even notarized ones)
Extension types:
compose extensions - allow new workflows when composing mail messages
action extensions - help people manage their inbox by providing custom rules on incoming messages
content blocking extensions - provide WebKit content blockers for Mail messages
message security extensions - provide further security by signing, encrypting, and decrypting messages when people send and receive mail
Creating a new Mail Extension
When you create a new Mail extension, you will be asked which types (among the ones above) your extension will be. This will enable/disable capabilities on your extension accordingly.
The principal class of your extension must conform to the MEExtension protocol.
MEExtensionexposes optional handler methods for each of the four types of extensionsAll the methods in
MEComposeSessionHandlerhave aMEComposeSessionargument which provides information about a compose window. Mail creates a uniqueMEComposeSessioninstance for every Mail compose window. Each window has aMEMessageproperty that exposes various details of the message being edited.
Compose extensions
Four ways your extension can interact with a Mail compose window:
validate/annotate recipient email addresses; as the user is editing them
present a view controller with additional context about the message being composed; the view controller must be a subclass of
MEExtensionViewControllerset additional headers on outgoing messages
validate/alert the user of errors in the message before it is sent
For MEComposeSession you will need to provide a MEComposeIcon and MEComposeIconToolTip entries in your extension Info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>MEComposeSession</key>
<dict>
<key>MEComposeIcon</key> // 👈🏻
<string>lock</string>
<key>MEComposeIconToolTip</key> // 👈🏻
<string>Recipient Validation Extension</string>
</dict>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.email.extension</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).MailExtension</string>
</dict>
</dict>
</plist>Example on how to validate recipient addresses:
func annotateAddressesForSession(_ session: MEMailComposeSession) async -> [String: MEAddressAnnotation] {
var annotations: [String: MEAddressAnnotation] = [:]
// Iterate through all the recipients in the message.
for address in session.mailMessage.allRecipientAddresses {
// Annotate invalid recipients with an error.
if address != "[email protected]" {
let message = "example.com is not a valid domain"
let annotation = MEAddressAnnotation.error(withLocalizedDescription: message)
annotations[address] = annotation
}
}
return annotations
}Action extensions
Three types:
mark messages as read and/or flag messages
move to other standard system mailboxes (e.g., Junk, Trash or Archive)
apply colors on messages in the message list
Your action extension must implement
MEMessageActionHandler’sdecideAction(for:completionHandler:)decideAction(for:completionHandler:)is called with aMEMessageargumentMail calls your handler’s decideAction for message for every new message that it downloads before it is even visible in the inbox.
Content blocking extensions
Your content blocking extension must implement an object conforming to
MEContentBlockerThe content rule lists are specified using the same syntax as Safari content blockers, e.g.:
[
{
"action": { "type": "block" },
"trigger": { "url-filter": "*.acme.*" }
},
...
]Message security extensions
Your content blocking extension must implement an object conforming to
MEMessageSecurityHandlereach time the sender or recipients change, Mail will call the
getEncodingStatus(for:completionHandler:)method on the extension’s message security handlerwhen the message is sent, Mail will take the RFC822 message data and pass it to the extension
the extension will sign and encrypt the message as needed, and return the signed and encrypted RFC822 data back to Mail. Mail will then send this data to the outgoing server
