Отправить приложение iphone по электронной почте программно - PullRequest
7 голосов
/ 19 октября 2011

Я пишу приложение для iPhone, которое требует, чтобы я отправлял вложение электронной почты программно. Вложение представляет собой CSV-файл, который я создаю с помощью кода. Затем я прикрепляю файл к электронному письму, и вложение отображается на телефоне. Однако, когда я отправляю письмо самому себе, вложение не появляется в электронном письме. Вот код, который я использую.

    [self exportData];

if ([MFMailComposeViewController canSendMail])
{
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"expenses" ofType:@"csv"];  
    NSData *myData = [NSData dataWithContentsOfFile:filePath]; 

    MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];

    mailer.mailComposeDelegate = self;

    [mailer setSubject:@"Vehicle Expenses from myConsultant"];

    NSString *emailBody = @"";
    [mailer setMessageBody:emailBody isHTML:NO];

    [mailer addAttachmentData:myData mimeType:@"text/plain" fileName:@"expenses"];

    [self presentModalViewController:mailer animated:YES];

    [mailer release]; 
}
else
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Failure"
                                                    message:@"Your device doesn't support the composer sheet"
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
    [alert release];
}
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
    switch (result)
    {
        case MFMailComposeResultCancelled:
            NSLog(@"Mail cancelled: you cancelled the operation and no email message was queued.");
            break;
        case MFMailComposeResultSaved:
            NSLog(@"Mail saved: you saved the email message in the drafts folder.");
            break;
        case MFMailComposeResultSent:
            NSLog(@"Mail send: the email message is queued in the outbox. It is ready to send.");
            break;
        case MFMailComposeResultFailed:
            NSLog(@"Mail failed: the email message was not saved or queued, possibly due to an error.");
        break;
        default:
            NSLog(@"Mail not sent.");
        break;
}

// Remove the mail view
[self dismissModalViewControllerAnimated:YES];

Создается успешно - я проверил в файлах симулятора.

- (void) exportData
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); 
    NSString *documentsDir = [paths objectAtIndex:0];
    NSString *root = [documentsDir stringByAppendingPathComponent:@"expenses.csv"];
    NSString *temp=@"Date,Purpose,Start Odometer,End Odometer, Total Driven, Fees, ";
    for(int i = 0; i < expenses.count; i++){
        VehicleExpense *tempExpense = [expenses objectAtIndex:i];
        temp = [temp stringByAppendingString:tempExpense.date];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:tempExpense.purpose];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.start_mile]];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.end_mile]];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.distance]];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.fees]];
        temp = [temp stringByAppendingString:@", "];
    }
    [temp writeToFile:root atomically:YES encoding:NSUTF8StringEncoding error:NULL];
    NSLog(@"got here in export data--- %@", documentsDir);

}

Ответы [ 3 ]

11 голосов
/ 19 октября 2011

попробовать [mailer addAttachmentData:myData mimeType:@"text/csv" fileName:@"expenses.csv"];

Edit: Вот код, который я использую в своем приложении:

- (IBAction) ExportData:(id)sender
{       
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:kExportFileName];

    self.timeRecords = [[NSMutableArray alloc] init];
    for (int i=0; i< [self.selectedTimeEntries count]; i++) 
        for (int j=0; j<[[self.selectedTimeEntries objectAtIndex:i] count]; j++) 
            if ([[self.selectedTimeEntries objectAtIndex:i] objectAtIndex:j] == [NSNumber numberWithBool:YES]) 
                [self.timeRecords addObject:[self timeEntriesForDay:[self.uniqueArray objectAtIndex:i] forIndex:j]];

    if( !([self.timeRecords count]!=0))
    {
        UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"There are no time entries selected!" message:@"Please select at least one time entry before proceeding" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];        
        return;
    }
    NSMutableString *csvLine;
    NSError *err = nil;
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    NSString *dateString = nil;
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    [numberFormatter setPositiveFormat:@"###0.##"];
    NSString *formattedNumberString = nil;

    if(![[NSFileManager defaultManager] fileExistsAtPath:filePath])        
    {
        [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
    }

    for (timeEntries *timeEntry in self.timeRecords) {
        csvLine = [NSMutableString stringWithString:timeEntry.client];
        [csvLine appendString:@","];
        [csvLine appendString:timeEntry.category];
        [csvLine appendString:@","];
        [csvLine appendString:timeEntry.task];
        [csvLine appendString:@","];
        dateString = [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:timeEntry.date]];
        [csvLine appendString:dateString];
        [csvLine appendString:@","];
        formattedNumberString = [numberFormatter stringFromNumber:timeEntry.duration];
        [csvLine appendString:formattedNumberString];
        [csvLine appendString:@","];
        [csvLine appendString:timeEntry.description];
        [csvLine appendString:@"\n"];

        if([[NSFileManager defaultManager] fileExistsAtPath:filePath])        
        {     
            NSString *oldFile = [[NSString alloc] initWithContentsOfFile:filePath];
            [csvLine insertString:oldFile atIndex:0];
            BOOL success =[csvLine writeToFile:filePath atomically:NO encoding:NSUTF8StringEncoding error:&err];
            if(success){

            }
            [oldFile release];
        }
    } 
    if (!appDelegate.shouldSendCSV) {
    self.csvText = csvLine;
    }
    if([[NSFileManager defaultManager] fileExistsAtPath:filePath])        
    {
        [self emailExport:filePath];
    }   
    self.selectedTimeEntries =nil;
    self.navigationController.toolbarHidden = NO;
}


- (void)emailExport:(NSString *)filePath
{
    NSLog(@"Should send CSV = %@", [NSNumber numberWithBool:appDelegate.shouldSendCSV]);
    MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
    picker.mailComposeDelegate = self;

    // Set the subject of email
    [picker setSubject:@"My Billed Time Export"];

    // Add email addresses
    // Notice three sections: "to" "cc" and "bcc"   

    NSString *valueForEmail = [[NSUserDefaults standardUserDefaults] stringForKey:@"emailEntry"];
    NSString *valueForCCEmail = [[NSUserDefaults standardUserDefaults] stringForKey:@"ccEmailEntry"];
    if( valueForEmail == nil ||  [valueForEmail isEqualToString:@""])
    {
        UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"Please set an email address before sending a time entry!" message:@"You can change this address later from the settings menu of the application!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];        

        return;
    }
    else {
        [picker setToRecipients:[NSArray arrayWithObjects:valueForEmail, nil]];
    }

    if(valueForCCEmail != nil || ![valueForCCEmail isEqualToString:@""])
    {
        [picker setCcRecipients:[NSArray arrayWithObjects:valueForCCEmail, nil]];
    }

    // Fill out the email body text
    NSString *emailBody = @"My Billed Time Export File.";

    // This is not an HTML formatted email
    [picker setMessageBody:emailBody isHTML:NO];

    if (appDelegate.shouldSendCSV) {

    // Create NSData object from file
    NSData *exportFileData = [NSData dataWithContentsOfFile:filePath];

    // Attach image data to the email 
    [picker addAttachmentData:exportFileData mimeType:@"text/csv" fileName:@"MyFile.csv"];
    } else {
        [picker setMessageBody:self.csvText isHTML:NO];
    }
    // Show email view  
    [self presentModalViewController:picker animated:YES];

    // Release picker
    [picker release];
}
3 голосов
/ 07 ноября 2017

Danut Pralea * ответ великолепен, однако код кажется слишком длинным для того, кто ищет простой способ до отправитьвложение по электронной почте программно .

Суть

Я сократил его ответ, чтобы вычеркнуть только важные биты, а также рефакторинг его так:

MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
mailComposer.mailComposeDelegate = self;

mailComposer.subject = @"Sample subject";

mailComposer.toRecipients = @[@"arthur@example.com", @"jeanne@example.com", ...];
mailComposer.ccRecipients = @[@"nero@example.com", @"mashu@example.com", ...];

[mailComposer setMessageBody:@"Sample body" isHTML:NO];

NSData *fileData = [NSData dataWithContentsOfFile:filePath];
[mailComposer addAttachmentData:fileData
                       mimeType:mimeType
                       fileName:fileName];

[self presentViewController:mailComposer animated:YES completion:nil];

По сути, это суть, этого достаточно, как есть.Например, если вы добавите этот код к действию кнопки, появится экран составления электронного письма с предварительно заполненными соответствующими полями, а также файл, который вы хотите прикрепить к электронному письму.

Дополнительная литература

Framework

MFMailComposeViewController находится под MessageUI Framework, поэтому для его использования следует импортировать (если вы этого не сделалипока) Фреймворк выглядит так:

#import <MessageUI/MessageUI.h>

Проверка работоспособности почты

Теперь, когда вы запускаете исходный код и еще не настроили почтовую учетную запись на своемустройство (не уверен, что поведение на симуляторе), этот код приведет к сбою вашего приложения.Похоже, что если учетная запись почты еще не настроена, выполнение [[MFMailComposeViewController alloc] init] все равно приведет к тому, что mailComposer будет равен нулю, вызовет сбой .Поскольку ответ в связанном вопросе гласит:

Вы должны проверить, может ли MFMailComposeViewController отправлять вашу почту непосредственно перед отправкой

Вы можете сделатьэто с помощью метода canSendMail следующим образом:

if (![MFMailComposeViewController canSendMail]) {
    [self openCannotSendMailDialog];
    return;
}

Вы можете исправить это перед выполнением [[MFMailComposeViewController alloc] init], чтобы вы могли немедленно уведомить пользователя.

Обработка notSendMail

Если canSendMail возвращает false, согласно Apple Dev Docs, это означает, что устройство не настроено для отправки почты.Это может означать , что, возможно, пользователь еще не настроил свою учетную запись Mail.Чтобы помочь пользователю с этим, вы можете предложить открыть приложение Почта и настроить его учетную запись.Вы можете сделать это следующим образом:

NSURL *mailUrl = [NSURL URLWithString:@"message://"];
if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) {
    [[UIApplication sharedApplication] openURL:mailUrl];
}

Затем вы можете реализовать openCannotSendMailDialog следующим образом:

- (void)openCannotSendMailDialog
{
    UIAlertController *alert =
        [UIAlertController alertControllerWithTitle:@"Error"
                                            message:@"Cannot send mail."
                                preferredStyle:UIAlertControllerStyleAlert];

    NSURL *mailUrl = [NSURL URLWithString:@"message://"];
    if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"Open Mail"
                                  style:UIAlertActionStyleDefault
                                handler:^(UIAlertAction * _Nonnull action) {
            [[UIApplication sharedApplication] openURL:mailUrl];
        }]];

        [alert addAction:
         [UIAlertAction actionWithTitle:@"Cancel"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {

        }]];

    } else {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"OK"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {

        }]];

    }

    [self presentViewController:alert animated:YES completion:nil];
}

Mime Types

Есликак и я, вы забыли / не уверены, какой mimeType использовать, здесь - это ресурс, который вы можете использовать.Скорее всего, достаточно text/plain, если прикрепляемый файл представляет собой простой текст или image/jpeg / image/png для изображений.

Делегат

Как вы, вероятно, заметили, XCode выдает нам предупреждение в следующей строке:

mailComposer.mailComposeDelegate = self; 

Это потому, что мы еще не настроили себя на соответствие соответствующему протоколу и реализацию его метода делегата.Если вы хотите получать события, независимо от того, была ли почта отменена, сохранена, отправлена ​​или даже не прошла отправку, вам нужно настроить свой класс на соответствие протоколу MFMailComposeViewControllerDelegate и обработать следующие события :

  • MFMailComposeResultSent
  • MFMailComposeResultSaved
  • MFMailComposeResultCancelled
  • MFMailComposeResultFailed
0 голосов
/ 24 октября 2011

Проблема заключалась в том, что я не искал подходящее место для файла.Спасибо @EmilioPalesz.

Вот код, который мне был нужен:

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); 
NSString *documentsDir = [paths objectAtIndex:0];
NSString *root = [documentsDir stringByAppendingPathComponent:@"expenses.csv"]

NSData *myData = [NSData dataWithContentsOfFile:root]; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...