使用附件和主题从外部应用程序打开Mail.app

时间:2011-12-06 10:49:40

标签: objective-c macos cocoa email-integration

我想打开Mail.app并指定要附加的主题和文件。我可以独立完成,但不能两者兼而有之。

要设置主题,我可以形成一个mailto:string和NSWorkspace openURL。

设置附件我可以使用

[[NSWorkspace sharedWorkspace] openFile:resolvedPath withApplication:@"Mail"];

我不知道相当于iOS的Mac的MacMailComposeViewController。我有什么选择?

3 个答案:

答案 0 :(得分:10)

NSString* subject = @"mail subject";
NSString* body = @"mail body";
NSString* to = @"recipient@example.org";

NSString *encodedSubject = [NSString stringWithFormat:@"SUBJECT=%@", [subject stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *encodedBody = [NSString stringWithFormat:@"BODY=%@", [body stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *encodedTo = [to stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *encodedURLString = [NSString stringWithFormat:@"mailto:%@?%@&%@", encodedTo, encodedSubject, encodedBody];
NSURL *mailtoURL = [NSURL URLWithString:encodedURLString];

[[NSWorkspace sharedWorkspace] openURL:mailtoURL];

答案 1 :(得分:0)

可以通过AppleScript轻松完成,“有趣”部分是如何从您的应用程序调用AppleScript。该文档应该为您提供所需内容:http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ScriptingBridgeConcepts/Introduction/Introduction.html

关于AppleScript的一个好处是你可以使用脚本编辑器找出你想要如何控制外部应用程序,然后在完成后在应用程序中对其进行编码。

答案 2 :(得分:-1)

编辑:此链接到的原始代码已被删除,因此我将其中一部分复制到此答案中。

您可以使用AppleScript(或Apple Events)来驱动Mail.app。这样做的好处是,您可以传递的附件大小没有限制,并且可以避免构建大量的URL。

在我们的软件中,我们使用以下内容编译合适的AppleScript:

- (NSAppleScript *)script
{
  if (script)
    return script;

  NSDictionary *errorInfo = nil;

  /* This AppleScript code is here to communicate with Mail.app */
  NSString *ourScript =
    @"on build_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                 attachfiles)\n"
    @"  tell application \"Mail\"\n"
    @"    set mailversion to version as string\n"
    @"    set msg to make new outgoing message at beginning of"
    @"      outgoing messages\n"
    @"    tell msg\n"
    @"      set the subject to subj\n"
    @"      set the content to msgbody\n"
    @"      if (sendr is not equal to \"\") then\n"
    @"        set sender to sendr\n"
    @"      end if\n"
    @"      repeat with rec in recip\n"
    @"        make new to recipient at end of to recipients with properties {"
    @"          name: |name| of rec, address: |address| of rec }\n"
    @"      end repeat\n"
    @"      repeat with rec in ccrec\n"
    @"        make new to recipient at end of cc recipients with properties {"
    @"          name: |name| of rec, address: |address| of rec }\n"
    @"      end repeat\n"
    @"      repeat with rec in bccrec\n"
    @"        make new to recipient at end of bcc recipients with properties {"
    @"          name: |name| of rec, address: |address| of rec }\n"
    @"      end repeat\n"
    @"      tell content\n"
    @"        repeat with attch in attachfiles\n"
    @"          make new attachment with properties { file name: attch } at "
    @"            after the last paragraph\n"
    @"        end repeat\n"
    @"      end tell\n"
    @"    end tell\n"
    @"    return msg\n"
    @"  end tell\n"
    @"end build_message\n"
    @"\n"
    @"on deliver_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                   attachfiles)\n"
    @"  set msg to build_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                           attachfiles)\n"
    @"  tell application \"Mail\"\n"
    @"    send msg\n"
    @"  end tell\n"
    @"end deliver_message\n"
    @"\n"
    @"on construct_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                     attachfiles)\n"
    @"  set msg to build_message(sendr, recip, subj, ccrec, bccrec, msgbody,"
    @"                           attachfiles)\n"
    @"  tell application \"Mail\"\n"
    @"    tell msg\n"
    @"      set visible to true\n"
    @"      activate\n"
    @"    end tell\n"
    @"  end tell\n"
    @"end construct_message\n";

  script = [[NSAppleScript alloc] initWithSource:ourScript];

  if (![script compileAndReturnError:&errorInfo]) {
    NSLog (@"Unable to compile script: %@", errorInfo);
    [script release];
    script = nil;
  }

  return script;
}

然后你可以使用像这样的代码触发脚本中的函数

- (NSAppleEventDescriptor *)descriptorForThisProcess
{
  ProcessSerialNumber thePSN = { 0, kCurrentProcess };

  return [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber
                            bytes:&thePSN
                               length:sizeof (thePSN)];
}

- (BOOL)doHandler:(NSString *)handler
       forMessage:(NSAttributedString *)messageBody
      headers:(NSDictionary *)messageHeaders
{
  NSMutableString *body = [NSMutableString string];
  NSDictionary *errorInfo = nil;
  NSAppleEventDescriptor *target = [self descriptorForThisProcess];
  NSAppleEventDescriptor *event
    = [NSAppleEventDescriptor appleEventWithEventClass:'ascr'
                           eventID:kASSubroutineEvent
                      targetDescriptor:target
                          returnID:kAutoGenerateReturnID
                     transactionID:kAnyTransactionID];
  NSAppleEventDescriptor *params = [NSAppleEventDescriptor listDescriptor];
  NSAppleEventDescriptor *files = [NSAppleEventDescriptor listDescriptor];
  NSString *tmpdir = NSTemporaryDirectory ();
  NSString *attachtmp = nil;
  NSFileManager *fileManager = [NSFileManager defaultManager];
  NSString *sendr = @"", *subj = @"";
  NSAppleEventDescriptor *recip
    = [self recipientListFromString:[messageHeaders objectForKey:@"To"]];
  NSAppleEventDescriptor *ccrec
    = [self recipientListFromString:[messageHeaders objectForKey:@"Cc"]];
  NSAppleEventDescriptor *bccrec
    = [self recipientListFromString:[messageHeaders objectForKey:@"Bcc"]];
  unsigned numFiles = 0;
  NSUInteger length = [messageBody length];
  NSUInteger pos = 0;
  NSRange range;

  if ([messageHeaders objectForKey:@"Subject"])
    subj = [messageHeaders objectForKey:@"Subject"];
  if ([messageHeaders objectForKey:@"Sender"])
    sendr = [messageHeaders objectForKey:@"Sender"];

  /* Find all the attachments and replace them with placeholder text */
  while (pos < length) {
    NSDictionary *attributes = [messageBody attributesAtIndex:pos
                           effectiveRange:&range];
    NSTextAttachment *attachment
      = [attributes objectForKey:NSAttachmentAttributeName];

    if (attachment && !attachtmp) {
      /* Create a temporary directory to hold the attachments (we have to do this
     because we can't get the full path from the NSFileWrapper) */
      do {
    attachtmp = [tmpdir stringByAppendingPathComponent:
                  [NSString stringWithFormat:@"csmail-%08lx",
                    random ()]];
      } while (![fileManager createDirectoryAtPath:attachtmp
                       withIntermediateDirectories:NO
                                        attributes:nil
                                             error:NULL]);
    }

    if (attachment) {
      NSFileWrapper *fileWrapper = [attachment fileWrapper];
      NSString *filename = [attachtmp stringByAppendingPathComponent:
                 [fileWrapper preferredFilename]];
      NSURL *url = [NSURL fileURLWithPath:filename isDirectory:NO];

      [fileWrapper writeToURL:url
                      options:NSFileWrapperWritingAtomic
          originalContentsURL:nil
                        error:NULL];

      [body appendFormat:@"<%@>\n", [fileWrapper preferredFilename]];

      [files insertDescriptor:
    [NSAppleEventDescriptor descriptorWithString:filename]
              atIndex:++numFiles];

      pos = range.location + range.length;

      continue;
    }

    [body appendString:[[messageBody string] substringWithRange:range]];

    pos = range.location + range.length;
  }

  /* Replace any CF/LF pairs with just LF; also replace CRs with LFs */
  [body replaceOccurrencesOfString:@"\r\n" withString:@"\n"
    options:NSLiteralSearch range:NSMakeRange (0, [body length])];
  [body replaceOccurrencesOfString:@"\r" withString:@"\n"
    options:NSLiteralSearch range:NSMakeRange (0, [body length])];

  [event setParamDescriptor:
    [NSAppleEventDescriptor descriptorWithString:handler]
         forKeyword:keyASSubroutineName];
  [params insertDescriptor:
    [NSAppleEventDescriptor descriptorWithString:sendr]
           atIndex:1];
  [params insertDescriptor:recip atIndex:2];
  [params insertDescriptor:
    [NSAppleEventDescriptor descriptorWithString:subj]
           atIndex:3];
  [params insertDescriptor:ccrec atIndex:4];
  [params insertDescriptor:bccrec atIndex:5];
  [params insertDescriptor:
    [NSAppleEventDescriptor descriptorWithString:body]
           atIndex:6];
  [params insertDescriptor:files atIndex:7];

  [event setParamDescriptor:params forKeyword:keyDirectObject];

  if (![[self script] executeAppleEvent:event error:&errorInfo]) {
    NSLog (@"Unable to communicate with Mail.app.  Error was %@.\n",
       errorInfo);
    return NO;
  }

  return YES;
}

- (BOOL)deliverMessage:(NSAttributedString *)messageBody
           headers:(NSDictionary *)messageHeaders
{
  return [self doHandler:@"deliver_message"
          forMessage:messageBody
         headers:messageHeaders];
}

- (BOOL)constructMessage:(NSAttributedString *)messageBody
         headers:(NSDictionary *)messageHeaders
{
  return [self doHandler:@"construct_message"
          forMessage:messageBody
         headers:messageHeaders];
}

上面的-constructMessage:headers:方法会导致Mail打开包含所有内容的新电子邮件,而-deliverMessage:headers:方法将创建并发送 e邮件一击。