4

I am trying to get my application to accept a mail message that was dropped onto my application's dock icon directly from Mail.

I have followed this link Dropping Files onto Dock Icon in Cocoa and tried to convert in into Swift and the latest version of Xcode but with no joy.

This is my AppDelegate.Swift file:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate
{
    func application(sender: NSApplication, openFile filename: String) -> Bool
    {
        println(filename)
        return true
    }

    func application(sender: NSApplication, openFiles filenames: [String])
    {
        println(filenames)
    }
}

I have set the document types for my project:

enter image description here

When I drag the mail document from Mail into the dock, then the dock highlights as if it wants to accept it but nothing triggers the openFiles method.

Incidentally if I drag the mail file out of Mail and into the Finder, and then drag it onto the dock icon it works fine.

And Mail drop only seems to work in El Capitan. I can see that mail can now be dropped into TextWrangler; this did not work under Yosemite.

As a bonus I'm offering an additional 50 bounty to anyone who can help me sort this out.

Community
  • 1
  • 1
iphaaw
  • 6,764
  • 11
  • 58
  • 83
  • 1
    possible duplicate of [Dropping Files onto Dock Icon in Cocoa](http://stackoverflow.com/questions/2489961/dropping-files-onto-dock-icon-in-cocoa) – mattt Jul 27 '15 at 19:38
  • I'd followed that question to get as far as I did, and distilled it into Swift but still couldn't get it to work. – iphaaw Jul 27 '15 at 20:19
  • I'm thinking that since you're dragging from one application to another you'll need to use Drag and Drop (see here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DragandDrop/DragandDrop.pdf -- it's in Cocoa, but browse through it anyways). I'm not 100% on this and I have done exactly 0 testing, hence a comment rather than an answer, but might be worth a looking into. – The Beanstalk Oct 02 '15 at 19:50

1 Answers1

1

You can extract the mail item's URL by registering your app as a service by adding the following to your app's info.plist:

<key>NSServices</key>
<array>
    <dict>
        <key>NSMessage</key>
        <string>itemsDroppedOnDock</string>
        <key>NSSendTypes</key>
        <array>
            <string>public.data</string>
        </array>
        <key>NSMenuItem</key>
        <dict>
            <key>default</key>
            <string>Open Mail</string>
        </dict>
    </dict>
</array>

Then your Swift app delegate would look like this:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    func applicationDidFinishLaunching(aNotification: NSNotification) {
        NSApp.servicesProvider = self
    }

    @objc func itemsDroppedOnDock(pboard: NSPasteboard, userData: NSString, error: UnsafeMutablePointer<NSString>) {
        // help from https://stackoverflow.com/questions/14765063/get-dropped-mail-message-from-apple-mail-in-cocoa
        print("dropped types: \(pboard.types)")
        if let types = pboard.types {
            for type in types {
                print(" - type: \(type) string: \(pboard.stringForType(type))")
            }
        }

    }
}

When you drop a mail message on your app's dock, the output will be something like:

dropped types: Optional(["public.url", "CorePasteboardFlavorType 0x75726C20", "dyn.ah62d4rv4gu8yc6durvwwaznwmuuha2pxsvw0e55bsmwca7d3sbwu", "Apple URL pasteboard type"])
 - type: public.url string: Optional("message:%3C2004768713.4671@tracking.epriority.com%3E")
 - type: CorePasteboardFlavorType 0x75726C20 string: Optional("message:%3C2004768713.4671@tracking.epriority.com%3E")
 - type: dyn.ah62d4rv4gu8yc6durvwwaznwmuuha2pxsvw0e55bsmwca7d3sbwu string: Optional("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<array>\n\t<string>message:%3C2004768713.4671@tracking.epriority.com%3E</string>\n\t<string></string>\n</array>\n</plist>\n")
 - type: Apple URL pasteboard type string: Optional("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<array>\n\t<string>message:%3C2004768713.4671@tracking.epriority.com%3E</string>\n\t<string></string>\n</array>\n</plist>\n")

Unfortunately, you probably need to figure out how to convert the mail URL "message:%3C2004768713.4671@tracking.epriority.com%3E" into the actual underlying mail file, but it's a start.

Alternatively, if you are willing to accept a drop in your app's window rather than on the dock, you should be able to just use NSDraggingInfo.namesOfPromisedFilesDroppedAtDestination, which is how I expect the Finder is able to copy the mail message when you drop one on a Finder window (note that the Finder does not respond to mail messages being dropped in its dock icon, only when they are dropped on a window).

Edit:

See Dropping promised files on to application icon in Dock on how to get promised file.

Community
  • 1
  • 1
marcprux
  • 9,845
  • 3
  • 55
  • 72
  • Thank you for your help. I can get my messages to drop into the dock now, but like you only got as far as the message: URL and cannot see how to get the message body. Bit further forward but stuck for now. – iphaaw Oct 05 '15 at 21:03
  • See [Dropping promised files on to application icon in Dock](http://stackoverflow.com/questions/33793386/dropping-promised-files-on-to-application-icon-in-dock). – catlan Nov 26 '15 at 17:50
  • I've tried implementing this answer (in ObjC) with NSSendTypes of NSSendTypes and unfortunately my pasteboard only has two types coming through: public.url-name and CorePasteboardFlavorType 0x75726C6E. Maybe new behavior in El Capitan? I'd be happy to get to the message:… URL but no luck even with that. – danwood Feb 09 '16 at 22:56