简体   繁体   中英

Apple Mail.app set HTML signature with plugin

I've created a Mail.app plugin with Python to set a custom signature pulled from a remote server by swizzling the setSignature: method in ComposeBackEnd. As per the class dump below, I can set a plain text signature by using setSignatureContents: and this is functional.

@interface Signature : NSObject <NSCopying>
{
    NSString *_uniqueId;
    NSString *_name;
    NSData *_webArchiveData;
    BOOL _isRich;
    BOOL _isSavedAsRich;
    BOOL _isDirty;
    MFSyncedFile *_syncedFile;
}

- (id)syncedFile;
- (id)signaturePath;
- (unsigned long long)hash;
- (BOOL)isEqual:(id)arg1;
- (BOOL)isRich;
- (void)setIsRich:(BOOL)arg1;
- (void)setWebArchive:(id)arg1;
- (id)webArchive;
- (id)webArchiveData;
.....
- (void)setSignatureContents:(id)arg1;
- (id)signatureContents;
- (void)setSignatureName:(id)arg1;
- (id)signatureName;

@end

However when I attempt to set an HTML signature using setWebArchive: (which should take an NSData object):

signature.setWebArchive_(NSData.dataWithContentsOfURL_(NSURL.URLWithString_('http://...')))

I get the following error:

11/7/12 11:07:38.858 AM Mail[8820]: -[NSConcreteData data]: unrecognized selector sent to instance 0x7ffc2386bc00

(The remote file is already in the correct format)

Is there any way to make this work? Thanks in advance.


EDIT - tried this (returns WebArchive object which should respond to -[data] ):

wds = WebDataSource.alloc().initWithRequest_(NSURLRequest.requestWithURL_(NSURL.URLWithString_('http://...')))
        webarchive = wds.webArchive
        signature.setWebArchive_(webarchive)

result:

11/7/12 3:26:59.173 PM Mail[16814]: An uncaught exception was raised
11/7/12 3:26:59.173 PM Mail[16814]: Class OC_PythonObject: no such selector: data

However when I attempt to set an HTML signature using setWebArchive: (which should take an NSData object)… I get the following error:

11/7/12 11:07:38.858 AM Mail[8820]: -[NSConcreteData data]: unrecognized selector

This error is telling you that -[setWebArchive:] is trying to call -[data] on your NSData object. Since -[NSData data] doesn't exist, you get an unrecognized selector exception.

Clearly it doesn't take an NSData , it takes something that responds to -[data] by returning an NSData .

EDIT - tried this (returns WebArchive object which should respond to -[data]):

wds = WebDataSource.alloc().initWithRequest_(NSURLRequest.requestWithURL_(NSURL.URLWithString_('http://...')))
webarchive = wds.webArchive
signature.setWebArchive_(webarchive)

Hold on… you haven't shown the class dump for this one, but the other class has a method -[webArchive] , not a properly webArchive . So, if they're at all consistent, this one is also likely to have a method, not a property.

If so, this means wds.webArchive is not going to be aa WebArchive object, it's going to be a wrapper object that represents roughly the ObjC equivalent of a Python bound method. And calling -[data] on that thing will almost certainly fail.

11/7/12 3:26:59.173 PM Mail[16814]: Class OC_PythonObject: no such selector: data

If you just change that to wds.webArchive() , that should fix the problem.

Finally, it's worth doing a bit of debugging prints here. If you think you've got a WebArchive and -[WebArchive data] returns an NSData , you can test that really easily:

print webArchive
print webArchive.data()

In case anyone is looking to do this, here's the solution to create and set a web archive (you'll need to add the WebKit framework):

WebView *webView = [[WebView alloc] init];
WebFrame *webFrame = [webView mainFrame];

NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://..."]];
[webFrame loadRequest:urlRequest];

-

WebDataSource *webDataSource = webFrame.dataSource;
WebArchive *webArchive = webDataSource.webArchive;
[signature setWebArchive:webArchive];

The code above after conversion to PyObjC syntax works great with the latest version of Mail. It can't be a local file unfortunately as Gatekeeper on 10.8 restricts it, and you have to call the URL request prior setSignature: (set webFrame as global variable and subclass the main window loading for instance) otherwise it won't load in time and you'll just get an empty WebArchive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM