如何从Cocoa发送HTML电子邮件?

时间:2021-03-16 22:50:59

I'm looking for a way to create a HTML formatted email from a OS X Cocoa application.

我正在寻找一种从OS X Cocoa应用程序创建HTML格式的电子邮件的方法。

My preferred workflow would be: The user selects a menu item and the default mail application opens with a pre-filled new email in the foreground.

我首选的工作流程是:用户选择一个菜单项,默认的邮件应用程序打开,前台有一个预先填好的新电子邮件。

I'm able to do this with mailto and -[NSWorkspace openURL] for plain text emails, but this doesn't work for HTML emails.

我可以使用mailto和 - [NSWorkspace openURL]来处理纯文本电子邮件,但这不适用于HTML电子邮件。

3 个解决方案

#1


I was interested in this too, so two days of reverse engineering Safaris 'Mail Contents of This Page' feature and I got it working.

我也对此感兴趣,所以两天逆向工程Safaris的“本页的邮件内容”功能,我得到了它的工作。

UPDATE: I improved the code and put it on GitHub

更新:我改进了代码并将其放在GitHub上

- (void)mailWebArchive:(WebArchive *)webArchive title:(NSString *)aTitle URL:(NSString *)aURL {
NSString *bundleID = @"com.apple.mail";
NSData* targetBundleID = [bundleID dataUsingEncoding:NSUTF8StringEncoding];
NSAppleEventDescriptor *targetDescriptor = nil;
NSAppleEventDescriptor *appleEvent = nil;

targetDescriptor = [NSAppleEventDescriptor descriptorWithDescriptorType:typeApplicationBundleID
                                                                   data:targetBundleID];
appleEvent = [NSAppleEventDescriptor appleEventWithEventClass:'mail'
                                                      eventID:'mlpg'
                                             targetDescriptor:targetDescriptor
                                                     returnID:kAutoGenerateReturnID
                                                transactionID:kAnyTransactionID];
[appleEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithDescriptorType:'tdta'
                                                                               data:[webArchive data]]
                    forKeyword:'----'];
[appleEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:aTitle]
                    forKeyword:'urln'];
[appleEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:aURL]
                    forKeyword:'url '];


NSAppleEventDescriptor *replyDescriptor = nil;
NSAppleEventDescriptor *errorDescriptor = nil;
AEDesc reply = { typeNull, NULL };  

// Send the AppleEvent
OSStatus status = AESendMessage([appleEvent aeDesc],
                    &reply,
                    kAEWaitReply,
                    kAEDefaultTimeout);
if(status == noErr)
{
    replyDescriptor = [[[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&reply] autorelease];
    errorDescriptor = [replyDescriptor paramDescriptorForKeyword:keyErrorNumber];
    if(errorDescriptor != nil)
        status = [errorDescriptor int32Value];

    if(status != noErr)
        NSLog(@"%s error %d", _cmd, status);
}
}

This code doesn't check if Mail is running, so it's only working when Mail is already started.

此代码不检查Mail是否正在运行,因此它仅在Mail已启动时才起作用。

The pro side of this approach that it works with all email clients which implement MailLinkSupported and MailPageSupported. See QA1722.

这种方法的专业方面,它适用于实现MailLinkSupported和MailPageSupported的所有电子邮件客户端。见QA1722。

The downside is that you can't set recipients like with a mailto. For this the Scripting Bridge seems the only solution. See this modified SBSendEmail sample.

缺点是你不能像mailto一样设置收件人。为此,Scripting Bridge似乎是唯一的解决方案。请参阅此修改后的SBSendEmail示例。

#2


There's no standard way to do complex interactions with arbitrary email clients. You would have to tackle each application you want to support separately, and see if it has a way to set the email format--most likely via Applescript--and then detect what the default mailto handler is and run the appropriate code. For some email clients, it may not be possible (just as some clients have no supported way to open a new email with an attachment).

没有标准的方法可以与任意电子邮件客户端进行复杂的交互。您必须单独处理要支持的每个应用程序,并查看它是否有办法设置电子邮件格式 - 最有可能通过Applescript - 然后检测默认的mailto处理程序是什么并运行相应的代码。对于某些电子邮件客户端,可能无法实现(正如某些客户端没有受支持的方式来打开带附件的新电子邮件)。

#3


Dustin Bachrach posted an elegant (but incomplete) solution here

Dustin Bachrach在这里发布了一个优雅(但不完整)的解决方案

It needs a bit of apple script, so you would have to create a different script for each mail app you want to support, but it seems like an easy thing to do.

它需要一些苹果脚本,所以你必须为你想要支持的每个邮件应用程序创建一个不同的脚本,但这似乎很容易。

You would also need to find the users default mail app which can be done by constructing a mailto: url then use LaunchServices LSGetApplicationForURL(): to return the default email client.

您还需要找到用户默认邮件应用程序,可以通过构建mailto:url然后使用LaunchServices LSGetApplicationForURL():来返回默认的电子邮件客户端。

#1


I was interested in this too, so two days of reverse engineering Safaris 'Mail Contents of This Page' feature and I got it working.

我也对此感兴趣,所以两天逆向工程Safaris的“本页的邮件内容”功能,我得到了它的工作。

UPDATE: I improved the code and put it on GitHub

更新:我改进了代码并将其放在GitHub上

- (void)mailWebArchive:(WebArchive *)webArchive title:(NSString *)aTitle URL:(NSString *)aURL {
NSString *bundleID = @"com.apple.mail";
NSData* targetBundleID = [bundleID dataUsingEncoding:NSUTF8StringEncoding];
NSAppleEventDescriptor *targetDescriptor = nil;
NSAppleEventDescriptor *appleEvent = nil;

targetDescriptor = [NSAppleEventDescriptor descriptorWithDescriptorType:typeApplicationBundleID
                                                                   data:targetBundleID];
appleEvent = [NSAppleEventDescriptor appleEventWithEventClass:'mail'
                                                      eventID:'mlpg'
                                             targetDescriptor:targetDescriptor
                                                     returnID:kAutoGenerateReturnID
                                                transactionID:kAnyTransactionID];
[appleEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithDescriptorType:'tdta'
                                                                               data:[webArchive data]]
                    forKeyword:'----'];
[appleEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:aTitle]
                    forKeyword:'urln'];
[appleEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:aURL]
                    forKeyword:'url '];


NSAppleEventDescriptor *replyDescriptor = nil;
NSAppleEventDescriptor *errorDescriptor = nil;
AEDesc reply = { typeNull, NULL };  

// Send the AppleEvent
OSStatus status = AESendMessage([appleEvent aeDesc],
                    &reply,
                    kAEWaitReply,
                    kAEDefaultTimeout);
if(status == noErr)
{
    replyDescriptor = [[[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&reply] autorelease];
    errorDescriptor = [replyDescriptor paramDescriptorForKeyword:keyErrorNumber];
    if(errorDescriptor != nil)
        status = [errorDescriptor int32Value];

    if(status != noErr)
        NSLog(@"%s error %d", _cmd, status);
}
}

This code doesn't check if Mail is running, so it's only working when Mail is already started.

此代码不检查Mail是否正在运行,因此它仅在Mail已启动时才起作用。

The pro side of this approach that it works with all email clients which implement MailLinkSupported and MailPageSupported. See QA1722.

这种方法的专业方面,它适用于实现MailLinkSupported和MailPageSupported的所有电子邮件客户端。见QA1722。

The downside is that you can't set recipients like with a mailto. For this the Scripting Bridge seems the only solution. See this modified SBSendEmail sample.

缺点是你不能像mailto一样设置收件人。为此,Scripting Bridge似乎是唯一的解决方案。请参阅此修改后的SBSendEmail示例。

#2


There's no standard way to do complex interactions with arbitrary email clients. You would have to tackle each application you want to support separately, and see if it has a way to set the email format--most likely via Applescript--and then detect what the default mailto handler is and run the appropriate code. For some email clients, it may not be possible (just as some clients have no supported way to open a new email with an attachment).

没有标准的方法可以与任意电子邮件客户端进行复杂的交互。您必须单独处理要支持的每个应用程序,并查看它是否有办法设置电子邮件格式 - 最有可能通过Applescript - 然后检测默认的mailto处理程序是什么并运行相应的代码。对于某些电子邮件客户端,可能无法实现(正如某些客户端没有受支持的方式来打开带附件的新电子邮件)。

#3


Dustin Bachrach posted an elegant (but incomplete) solution here

Dustin Bachrach在这里发布了一个优雅(但不完整)的解决方案

It needs a bit of apple script, so you would have to create a different script for each mail app you want to support, but it seems like an easy thing to do.

它需要一些苹果脚本,所以你必须为你想要支持的每个邮件应用程序创建一个不同的脚本,但这似乎很容易。

You would also need to find the users default mail app which can be done by constructing a mailto: url then use LaunchServices LSGetApplicationForURL(): to return the default email client.

您还需要找到用户默认邮件应用程序,可以通过构建mailto:url然后使用LaunchServices LSGetApplicationForURL():来返回默认的电子邮件客户端。