从Cocoa发送电子邮件

16

我如何在不使用任何电子邮件客户端的情况下从Cocoa应用程序发送电子邮件?我有NSURL但它会打开一个电子邮件客户端。我希望在没有此类情况发生的情况下发送电子邮件。


可能是重复的问题:Pantomime = 过时的邮件发送和接收框架 - Sherm Pendley
可能是[发送电子邮件 - Cocoa]的重复问题(https://dev59.com/yEnSa4cB1Zd3GeqPMUOv)。 - Jens Ayton
4个回答

30

这些响应已经过时,对于 Mac OS X 10.8 及以上版本,您应该使用 NSSharingService。

NSArray *shareItems=@[body,imageA,imageB];
NSSharingService *service = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];
service.delegate = self;
service.recipients=@[@"xxx@apple.com"];
service.subject= [ NSString stringWithFormat:@"%@ %@",NSLocalizedString(@"SLYRunner console",nil),currentDate];
[service performWithItems:shareItems];

共享服务文档页面


1
这应该是被接受的答案。但要注意,如果用户使用Outlook,则附件不会被附加。 - fzwo
3
@ZS 这不是正确的。请参考 performWithItems: 来设置消息正文。 - insys
1
NSSharingService 是 10.8+ 版本可用,但 recipientssubject 属性仅在 10.9+ 版本以上可用,因此如果你的目标是 10.8 版本,应该添加一个 respondToSelector: 测试。 - Vincent Tourraine
更新:Yosemite也是同样的情况。我认为我需要将一些框架链接到应用程序中,但不确定是哪些框架。 - Hedin
1
更新:对于遇到相同错误的人:ShareKit仅支持64位。 - Hedin
显示剩余4条评论

29

更新:正如其他人建议的那样,从 10.9 版本开始,您可以使用 NSSharingService,它也支持附件!

Swift 示例:

    let emailImage          = NSImage.init(named: "ImageToShare")!
    let emailBody           = "Email Body"
    let emailService        =  NSSharingService.init(named: NSSharingServiceNameComposeEmail)!
    emailService.recipients = ["support@myapp.com"]
    emailService.subject    = "App Support"

    if emailService.canPerform(withItems: [emailBody,emailImage]) {
        // email can be sent
        emailService.perform(withItems: [emailBody,emailImage])
    } else {
        // email cannot be sent, perhaps no email client is set up
        // Show alert with email address and instructions

    }

旧更新: 我之前的答案一直有效,直到我不得不为应用商店对我的应用进行沙盒处理。自那以后,我找到的唯一解决方案就是简单使用一个 mailto: 链接。

- (void)sendEmailWithMail:(NSString *) senderAddress Address:(NSString *) toAddress Subject:(NSString *) subject Body:(NSString *) bodyText {
    NSString *mailtoAddress = [[NSString stringWithFormat:@"mailto:%@?Subject=%@&body=%@",toAddress,subject,bodyText] stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:mailtoAddress]];
    NSLog(@"Mailto:%@",mailtoAddress);
}

缺点:无附件!如果您知道如何在Mac上运行它,请告诉我!

旧答案:您可以使用Apple Script,苹果公司的脚本桥接框架(解决方案2)或Python脚本(解决方案3)

解决方案1(Apple脚本):

attachments是包含文件路径的字符串数组

- (void)sendEmailWithMail:(NSString *) toAddress withSubject:(NSString *) subject Attachments:(NSArray *) attachments { 
NSString *bodyText = @"Your body text \n\r";    
NSString *emailString = [NSString stringWithFormat:@"\
                         tell application \"Mail\"\n\
                         set newMessage to make new outgoing message with properties {subject:\"%@\", content:\"%@\" & return} \n\
                         tell newMessage\n\
                         set visible to false\n\
                         set sender to \"%@\"\n\
                         make new to recipient at end of to recipients with properties {name:\"%@\", address:\"%@\"}\n\
                         tell content\n\
                         ",subject, bodyText, @"McAlarm alert", @"McAlarm User", toAddress ];

//add attachments to script
for (NSString *alarmPhoto in attachments) {
    emailString = [emailString stringByAppendingFormat:@"make new attachment with properties {file name:\"%@\"} at after the last paragraph\n\
                   ",alarmPhoto];

}
//finish script
emailString = [emailString stringByAppendingFormat:@"\
               end tell\n\
               send\n\
               end tell\n\
               end tell"];



//NSLog(@"%@",emailString);
NSAppleScript *emailScript = [[NSAppleScript alloc] initWithSource:emailString];
[emailScript executeAndReturnError:nil];
[emailScript release];

/* send the message */
NSLog(@"Message passed to Mail");

}

Solution 2(苹果ScriptingBridge框架): 您可以使用苹果的ScriptingBridge框架来使用Mail发送邮件。 苹果示例链接,非常简单,您只需要调整添加规则和Mail.app到您的项目中。仔细阅读Readme.txt。

将“emailMessage.visible = YES;”更改为“emailMessage.visible = NO;”,以便在后台发送。

缺点:用户需要在Mail下拥有有效帐户。

Solution 3(Python脚本(无用户帐户): 您还可以使用Python脚本发送消息。 缺点:用户必须输入SMTP详细信息,除非您从Mail中获取它们(但然后您可以直接使用上述解决方法1),或者您必须在应用程序中硬编码可靠的SMTP中继(您可以设置一个gmail帐户并将其用于此目的,但如果您的应用程序发送太多电子邮件,谷歌可能会删除您的帐户(SPAM)) 我使用这个Python脚本:

import sys
import smtplib
import os
import optparse

from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders

username = sys.argv[1]
hostname = sys.argv[2]
port = sys.argv[3]
from_addr = sys.argv[4]
to_addr = sys.argv[5]
subject = sys.argv[6]
text = sys.argv[7]

password = getpass.getpass() if sys.stdin.isatty() else sys.stdin.readline().rstrip('\n')

message = MIMEMultipart()
message['From'] = from_addr
message['To'] = to_addr
message['Date'] = formatdate(localtime=True)
message['Subject'] = subject
#message['Cc'] = COMMASPACE.join(cc)
message.attach(MIMEText(text))

i = 0
for file in sys.argv:
    if i > 7:
        part = MIMEBase('application', 'octet-stream')
        part.set_payload(open(file, 'rb').read())
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file))
        message.attach(part)
    i = i + 1

smtp = smtplib.SMTP(hostname,port)
smtp.starttls()
smtp.login(username, password)
del password

smtp.sendmail(from_addr, to_addr, message.as_string())
smtp.close()

我使用这个方法调用它,以便使用Gmail账户发送电子邮件。

- (bool) sendEmail:(NSTask *) task toAddress:(NSString *) toAddress withSubject:(NSString *) subject Attachments:(NSArray *) attachments {

        NSLog(@"Trying to send email message");
        //set arguments including attachments
        NSString *username = @"my.gmail.account@gmail.com";
        NSString *hostname = @"smtp.gmail.com";
        NSString *port = @"587";
        NSString *fromAddress = @"my.gmail.account@gmail.com";  
        NSString *bodyText = @"Body text \n\r"; 
        NSMutableArray *arguments = [NSMutableArray arrayWithObjects:
                                    programPath,
                                    username,
                                    hostname,
                                    port, 
                                    fromAddress, 
                                    toAddress,
                                    subject,
                                    bodyText, 
                                    nil];  
        for (int i = 0; i < [attachments count]; i++) {
            [arguments addObject:[attachments objectAtIndex:i]];
        }

        NSData *passwordData = [@"myGmailPassword" dataUsingEncoding:NSUTF8StringEncoding];


        NSDictionary *environment = [NSDictionary dictionaryWithObjectsAndKeys:
                                     @"", @"PYTHONPATH",
                                     @"/bin:/usr/bin:/usr/local/bin", @"PATH",
                                     nil];
        [task setEnvironment:environment];
        [task setLaunchPath:@"/usr/bin/python"];

        [task setArguments:arguments];

        NSPipe *stdinPipe = [NSPipe pipe];
        [task setStandardInput:stdinPipe];

        [task launch];

        [[stdinPipe fileHandleForReading] closeFile];
        NSFileHandle *stdinFH = [stdinPipe fileHandleForWriting];
        [stdinFH writeData:passwordData];
        [stdinFH writeData:[@"\n" dataUsingEncoding:NSUTF8StringEncoding]];
        [stdinFH writeData:[@"Description" dataUsingEncoding:NSUTF8StringEncoding]];
        [stdinFH closeFile];

        [task waitUntilExit];

        if ([task terminationStatus] == 0) { 
            NSLog(@"Message successfully sent");
            return YES;
        } else {
            NSLog(@"Message not sent");
            return NO;
        }
    }

希望这能有所帮助。


1
脚本桥...如果我使用Thunderbird呢?或者Outlook?或者其他什么? - Dave DeLong
然后您可以使用Perl脚本。Mail是最流行的电子邮件客户端,如果不存在,则可以要求用户输入其SMTP详细信息,或者您可以硬编码自己的详细信息。 - Tibidabo
2
你可以尝试使用[[NSWorkspace sharedWorkspace] openFile:filePath withApplication:@"Mail"]来创建一个带附件的新邮件。但是你无法预填收件人,而且你需要访问共享文件夹才能将文件保存到其中(例如下载文件夹)。 - Martin Hering
2
你可以尝试在Mavericks中使用新的NSSharingService: 'NSSharingService *service = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail]; [service setRecipients:[NSArray arrayWithObject:@"Your email"]]; [service setSubject:@"Your subject"]; [service performWithItems:yourAttachments, nil];' - Mark Bridges

3

这篇文章会对你有所帮助,它引用了示例代码

同时,你需要修改Controller.m中的第114行,以便在后台发送消息:

emailMessage.visible = NO;

我之前看过那篇帖子,但是当你发送邮件时它会打开邮件应用程序,而我并不想要这个,我只想发送邮件,基本上我想制作自己的邮件应用程序: ),但还是谢谢你的回答:D - Lenny Magico

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接