Dragging and Dropping Emails from Apple Mail Into Swift Apps

I’m building an app that needs to be able to accept emails via drag and drop from Apple’s own Mail.app. However, it turns out that there (seems to be) a bug in how Mail.app is treating drag and drop that prevents you from just receiving an email as a file.

Here’s a description of that bug and a valid workaround to solve it. You can find source code demonstrating the bug on GitHub as well as a branch of the same repo with sample code for the workaround.

The Problem

Receiving mails from Mail.app works by configuring an NSFilePromiseReceiver to receive promises of .eml files (a file-based representation of emails) from any other app on the system.

Typically, the app that provides the files (Mail.app) promises to place the files that have been dragged into and accepted by the receiving app (our app) into a location of the receiving apps choosing. Once that’s done, a callback function inside the receiving app is called.

However, the File Promise that you get from Apple Mail’s dragging pasteboard never properly resolves. That is, the code for resolving the promise will hang for exactly one minute and then return an NSURL error.

But: Apple Mails still writes the requested file to the correct destination. It’s just the file promise code block that fails.

The NSURL error looks something like this:

- Error Domain=NSURLErrorDomain Code=-1001 "(null)"

I know that this is an Apple Mail specific issue because Microsoft Outlook will work just fine, writing the .eml to the correct location and resolving the promise without issue.

I’ve also opened a paid code-level support ticket with Apple Developer, which has been closed & refunded fairly quickly since the engineer at Apple could only direct me to file a bug report with the Apple Mail team.

So right now, Apple Mail drag and drop seems to just… be broken. Now what?

The Workaround

The workaround here is fairly straight forward: Don’t expect the file promise callback to ever get called.

Instead, use the File System Events API to watch the directory your app provides to the File Promise. This way, you’ll get a callback when Apple Mail has placed the email message into the correct location and can work with it, even if the promise never properly resolves to your callback code.

You can find the full sample code in my GitHub repo, but here’s the part that’s interesting if you’re just looking fo a workaround. (I’m using the Witness library as a Swift-wrapper around the low-level FileSystem API here)

The Solution

For now, this workaround appears to be the only way of receiving emails via drag and drop. If you know a better workaround, a fix for the issue or want to tell me that I’ve just gotten it wrong in my implementation in the first place, please do eMail me.