Meet MailKit: the best way to build amazing experiences on top of Mail. MailKit enables apps to easily and securely interact with the Mail app for macOS. We'll deep dive into the MailKit API, and show you how to create extensions for composing messages, message actions, secure email, and content blocking.
Hello. Mail is a crucial application, and Mail app extensions will let you enhance it in some incredible new ways. I'm Abhilash, and along with my colleague, Seth, we are going to walk you through how to build great Mail app extensions. In macOS Monterey, we are shipping a new framework, MailKit, for building Mail extensions. These extensions are built on the same underlying foundation as other app extensions like Safari app extensions and share sheet extensions. They are built with user privacy and security in mind in mind from the ground up. MailKit APIs are well documented and will be supported across major macOS releases. Like other app extensions, they can be in any properly signed Mac app, can be bundled in your existing apps, and can also be distributed in the App Store. Mail extensions are the future of extending Mail. Plug-ins will stop functioning in a future macOS release. We are introducing four new ways you can extend Mail's user experience. First, compose extensions will 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. Finally, message security extensions can provide further security by signing, encrypting, and decrypting messages when people send and receive mail. This provides a full suite of Mail extensions to help compose messages, take action on incoming messages, block undesired mail content and provide encryption and decryption. They are easy to write. They are very powerful. They are stable and will continue to work as the OS and Mail app change over time. Before we dive in to build a Mail extension with these capabilities, let's go through an example of one in use. Imagine I am working for a large multinational corporation where all my colleagues are collaborating on multiple highly secretive projects. To help preserve secrecy of our projects, we are using a Big Secrecy Extension that validates recipients of a mail message. I want to send a message to my colleague Seth for an update on our new remote office on Mars. The first thing you notice is a button for the Big Secrecy Extension in the Mail compose window. This extension provides a list of projects I'm working on, and I pick Mars Remote Office. I type in a subject and Seth's email. The extension was able to validate that Seth is disclosed on this project and annotates his email address with a blue checkmark. Of course, for a project of this importance, we do want to keep our manager, Mikey, informed, so I'm going to add him. Hmm, looks like Mikey is not disclosed about our new remote office. Let me remove him and send the message.
Oh, I received a reply from Seth, and it shows up in red in the message list. This is because the Big Secrecy Extension performed an action to color messages regarding the Mars project as red. There is also an icon indicating that an extension performed an action on this message. When I go to view the message, there is an icon in the Message Viewer indicating that the message from Seth was encrypted and successfully decrypted by the Big Secrecy Extension.
Now let's dive in and learn how you can leverage MailKit APIs to build powerful extensions like the Big Secrecy Extension. Let's start with compose extensions which can provide new features for users while composing messages. In macOS Monterey, there are four ways your extension can interact with a Mail compose window.
An extension can validate recipient email addresses as the user is editing them, provide a view controller with additional context about the message being composed, set additional headers on outgoing messages, or alert the user of errors in the message before it is sent.
Let's walk through how to build a compose extension.
You start by adding a new target to an existing macOS App. In Xcode 13, there is a new Mail Extension template that will get you started on creating a new Mail Extension target. During setup, Xcode will allow you to choose the type of extension you want to create. For a compose extension, you select the Include Compose Session Handler capability.
In the Info.plist for the extension target, you must also specify an icon and a descriptive tooltip in the MEComposeSession dictionary. Mail will use the icon and tooltip to display a toolbar button in the compose window. Now let's look at the implementation for your extension's principal class. The principal class of your extension must conform to the MEExtension protocol. MEExtension exposes optional handler methods for each of the four types of extensions. For a compose extension, your principal class must implement the handler for session method and return an instance that conforms to the MEComposeSessionHandler protocol. Methods in MEComposeSessionHandler are called by Mail to inform the extension about a Compose window's life cycle. The first method that will be called is ComposeSessionDidBegin, which happens when a new compose window is opened. There are also methods that are called based on user actions like editing recipient email addresses or sending an email.
All the methods in MEComposeSessionHandler have a MEComposeSession argument which provides information about a compose window. Mail creates a unique MEComposeSession instance for every Mail compose window. It has a MEMessage property that exposes various details of the message being edited. You can utilize this information to customize the responses that you provide when Mail calls your extension's MEComposeSessionHandler methods. Let's look at an example of how you can do this to annotate recipient email addresses.
Mail will call your ComposeSessionHandler's annotateAddressesForSession whenever recipient addresses are edited. In this example, we are using the allRecipientAddresses property of MEMessage to provide an error annotation for emails that are not matching firstname.lastname@example.org. Compose extensions can also provide a view controller that Mail will display in the compose window. Your view controller can provide valuable context to the user by customizing the view controller for each compose window. Your extension's view controller must be a subclass of MEExtensionViewController. Mail will request an instance of this view controller by calling the viewControllerForSession method of MEComposeSessionHandler.
You can learn more about these compose APIs in the MailKit documentation and get started on building new workflows. Now let's talk about Mail action extensions. Action extensions perform actions on incoming messages to help users manage their inbox. In macOS Monterey, we are exposing three types of actions an extension can perform on a new message. An action extension can modify read status and flags of incoming messages, move messages to system mailboxes such as Junk, Trash or Archive, or apply colors to messages when they are displayed in the message list. You can add support for message actions by selecting the Include Message Action Handler capability when you are creating the Mail extension target. Similar to the compose extension, for action extensions, your principal class must return a message action handler by implementing a handler for message actions. In this example, the principal class is also acting as an action handler by adopting MEMessageActionHandler. Your action extension must implement MEMessageActionHandler's decideAction for message method. DecideAction for message is called with a MEMessage argument. Here, we are coloring the message red by checking if the headers property contains "Mars." A few things to note about action handlers. Mail calls your handler's decideAction for message for every new message that it downloads before it is even visible in the inbox. The first time Mail calls your extension's decideAction for message method, the MEMessage instance will have only a subset of the message headers. You can provide a decision such as coloring the message based on the available headers. Once Mail applies the action on the message, it will be visible in the inbox. In some cases, you will need the complete body and headers of the message to return an appropriate decision. In this case, your decideAction for message method can return an invokeAgainWithBody decision. This will cause Mail to fetch the complete message body and headers before invoking your handler's decideAction for message method again. You can now return a more accurate decision before it is visible in the inbox. Now I am going to turn it over to Seth, who will to show you how to build content blocking and security extensions. Thanks, Abhilash. First, I am going to walk you through how to add a content blocker extension. Content blockers hook into Mail's WebKit configuration for its message view to allow extensions to block loading content based on triggers in the message's HTML. This allows extensions to block loading content based on criteria of the HTML such as the URL. In this example, the extension was able to block loading the remote images based on the rules in the extension's content rule list. You can add support for content blocking by selecting Include Content Blocker when you are creating the Mail extension target. Next, you return a handler for the content blocker in your extension's principal class. In this example, the principal class is adopting the MEContentBlocker protocol so it returns self. The content rule lists are specified using the same syntax as Safari content blockers. So if you already have a content rule list for your Safari content blocker extension, you can use the same rules for a Mail app extension as well. You can get more information on how to create a content rule list by referencing the "Introduction to Webkit Content Blockers" documentation. Once your rule list is complete, you can provide it to Mail by returning it in the contentRulesJSON method. This method expects a Data encoding of the Content Rule List JSON. And that's it for Mail content blockers. Lastly, we're going to go over Message security extensions. The Message security capability gives extensions the ability to encode and decode encrypted messages. They can also sign messages and provide a way to view certificates of signed messages. You can add support for message security by selecting Include Message Security Handler when you're creating the Mail extension target. Next, you need to return a handler from your extension that supports the MEMessageSecurityHandler protocol in our extension's principal class. In this example, the extension's principal class is also adopting the MEMessageSecurityHandler protocol, so it returns self. Now let's take a look at how to encode messages that are being composed. Encoding a message is broken down into two parts. The first helps drive the UI as the message is composed. This lets the extension show if it has the ability to sign and encrypt the current message. The next part is to actually encrypt and sign the message as it is being sent. As a message is composed, Mail will send the message, including the sender and current list of recipients to the extension. The extension can then determine if it has the ability to sign and encrypt the message. Based on what is returned by the extension, Mail will highlight the Lock and Certificate icons, depending on if the message can be signed and encrypted.
Each time the sender or recipients change, Mail will call the getEncodingStatus method on the extension's message security handler. The extension will verify if it can sign and encrypt the message and return to Mail the current encoding status. The example here is importing an ExampleEncoder to do the actual work of checking the encoding status of the message. The Message Security Handler returns the status once available. Next, when 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.
When the message is ready to send, Mail passes the current message using the encodeMessage method to the extension's Message Security Handler. The extension's Message Security Handler will return the encoded message. Again, in this example, we're using an ExampleEncoder to do the actual work of encoding the message. The Message Security Handler returns encoded message. Message decoding works similarly but in reverse. When the message is viewed, Mail will send the encoded RFC822 message data to the extension. The extension will decode the message into nonencrypted, or signed, RFC822 data and return that back to Mail. Mail will then display the decoded message.
When Mail is ready to decode the message, it will call into the Extension's Security Handler calling the decodedMessage method. If the extension has the ability to decode the message, it will do so and return the decoded RFC822 message. If the extension is not needed for decoding the message, it should quickly return nil. When a message is viewed, it can be determined if it is signed and encrypted. For signed messages, the signer certificate can be clicked next to the signer label to view the sender's certificate information. Mail allows extensions to provide its own view controller to render this certificate information. As part of the decoded Mail message, the extension has the ability to return a set of message signers. The label provided will be shown as the signer in the message view. The extension can also populate the context property with any information it might need for displaying the signing certificate. When the certificate icon is clicked, Mail requests a ViewController from the extension and passes it the set of signers for the current message. These signers are what was returned to Mail by the extension when the message was originally decoded. The view controller must be a subclass of MEExtensionViewController. And that's it for message security extensions. Mail extensions are a powerful new way for you to enhance the Mail experience. We're excited to see how you leverage these Mail capabilities to build awesome new products, and we want to hear your feedback. So send us an email or post a message on our Developer Forums. These examples show the power of Mail app extensions. We made a compose extension that verified recipients, an action extension that colored incoming messages. We saw a content blocker blocking remote images. Last, we saw how easy it is to add custom encryption and decryption to Mail. In this video, we covered how to build Mail app extensions. We're looking forward to see how you extend Mail to do some really cool things. So get out there and build some awesome new Mail app extensions. Thanks for watching.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.