swift2 从swift osx应用程序发送电子邮件

fv2wmkja  于 2022-11-06  发布在  Swift
关注(0)|答案(3)|浏览(259)

我正面临着从我的osx swift应用程序发送邮件的问题。为了发送邮件,我使用了下面的代码

import Foundation
import Cocoa

class sendemail : NSObject, NSSharingServiceDelegate{

func sendEmail()  throws
{
    print("enter email sending")
    let body = "This is an email for auto testing throug code."
    let shareItems = [body] as NSArray

    let service = NSSharingService(named: NSSharingServiceNameComposeEmail)

    service?.delegate = self
    service?.recipients = ["abc@dom.com"]

    let subject = "Vea Software"
    service?.subject = subject

    service?.performWithItems(shareItems as [AnyObject])
}

}

我找到了这个链接的来源:https://www.veasoftware.com/posts/send-email-in-swift-xcode-62-os-x-1010-tutorial
但它不起作用。
我还尝试按照以下说明从终端发送邮件:
http://www.developerfiles.com/how-to-send-emails-from-localhost-mac-os-x-el-capitan/
它说:

postfix/postfix-script: fatal: the Postfix mail system is not running

请帮帮我。
我可以从我的mac邮件应用程序手动发送邮件,这是配置。
我正在使用

xcode 7.3, osx el captain and swift 2.2
bnlyeluc

bnlyeluc1#

现代雨燕:

func sendEmail(to recipients: [String], subject: String, body: String) {
    let service = NSSharingService(named: .composeEmail)!
    service.recipients = recipients
    service.subject = subject
    service.perform(withItems: [body])
}

// Usage
sendEmail(
    to: ["abc@dom.com"],
    subject: "Vea software",
    body: "This is an email for auto testing through code."
)

本地用户必须有一个Mail.app帐户。你还需要一个NSApplication的示例来运行它。不能在CLI应用程序中这样做。如果你在控制台中看到以下错误,这意味着你没有活动的NSApplication示例。

[default] 0 is not a valid connection ID

原始答案

这对我很有效:

import Cocoa

class SendEmail: NSObject {
    static func send() {
        let service = NSSharingService(named: NSSharingServiceNameComposeEmail)!
        service.recipients = ["abc@dom.com"]
        service.subject = "Vea software"

        service.performWithItems(["This is an email for auto testing through code."])
    }
}

用法:

SendEmail.send()
56lgkhnf

56lgkhnf2#

斯威夫特4.2:

class SendEmail: NSObject {
    static func send() {
        let service = NSSharingService(named: NSSharingService.Name.composeEmail)!
        service.recipients = ["email@yourEmail.eu"]
        service.subject = "Email Subject"

        service.perform(withItems: ["Email Content"])
    }
}

用法:SendEmail.send()

zysjyyx4

zysjyyx43#

我们通过使用postfix实用程序而不是共享服务来解决这个问题。注意,在下面的代码生效之前,postfix必须运行并正确配置。
为什么要这么做呢?嗯,这是一个稍微更“通用”的解决方案,应该可以在macOS以外的平台上工作(或者可以很容易地修改)。而且,它不依赖于“邮件”。
请注意,这也使用了我们的Log工具,但您应该能够轻松地提取所需的代码。

/// This queue/thread will be used to transfer the mails.

fileprivate let mailQueue = DispatchQueue.global(qos: .background)

/// Sends an email using the postfix unix utility.
///
/// - Note: Ths function only works if postfix is running (and set up correctly)
///
/// - Parameters:
///   - mail: The email to be transmitted. It should -as a minimum- contain the To, From and Subject fields.
///   - domainName: The domain this email is sent from, used for logging purposes only.

public func sendEmail(_ mail: String, domainName: String) {

    // Do this on a seperate queue in the background so this operation is non-blocking.

    mailQueue.async { [mail, domainName] in

        // Ensure the mail is ok

        guard let utf8mail = mail.data(using: .utf8), utf8mail.count > 0 else {
            Log.atDebug?.log("No mail present")
            return
        }

        let options: Array<String> = ["-t"] // This option tells sendmail to read the from/to/subject from the email string itself.

        let errpipe = Pipe() // should remain empty
        let outpipe = Pipe() // should remain empty (but if you use other options you may get some text)
        let inpipe = Pipe()  // will be used to transfer the mail to sendmail

        // Setup the process that will send the mail

        let process = Process()
        if #available(OSX 10.13, *) {
            process.executableURL = URL(fileURLWithPath: "/usr/sbin/sendmail")
        } else {
            process.launchPath = "/usr/sbin/sendmail"
        }
        process.arguments = options
        process.standardError = errpipe
        process.standardOutput = outpipe
        process.standardInput = inpipe

        // Start the sendmail process

        let data: Data
        do {

            Log.atDebug?.log("\n\(mail)")

            // Setup the data to be sent

            inpipe.fileHandleForWriting.write(utf8mail)

            // Start the sendmail process

            if #available(OSX 10.13, *) {
                try process.run()
            } else {
                process.launch()
            }

            // Data transfer complete

            inpipe.fileHandleForWriting.closeFile()

            // Set a timeout. 10 seconds should be more than enough.

            let timeoutAfter = DispatchTime(uptimeNanoseconds: DispatchTime.now().uptimeNanoseconds + UInt64(10000) * 1000000)

            // Setup the process timeout on another queue

            DispatchQueue.global().asyncAfter(deadline: timeoutAfter) {
                [weak process] in
                Log.atDebug?.log("Sendmail Timeout expired, process \(process != nil ? "is still running" : "has exited already")")
                process?.terminate()
            }

            // Wait for sendmail to complete

            process.waitUntilExit()

            Log.atDebug?.log("Sendmail terminated")

            // Check termination reason & status

            if (process.terminationReason == .exit) && (process.terminationStatus == 0) {

                // Exited OK, return data

                data = outpipe.fileHandleForReading.readDataToEndOfFile()

                if data.count > 0 {
                    Log.atDebug?.log("Unexpectedly read \(data.count) bytes from sendmail, content: \(String(data: data, encoding: .utf8) ?? "")")
                } else {
                    Log.atDebug?.log("Sendmail completed without error")
                }

            } else {

                // An error of some kind happened

                Log.atError?.log("Sendmail process terminations status = \(process.terminationStatus), reason = \(process.terminationReason.rawValue )")

                let now = dateFormatter.string(from: Date())

                Log.atError?.log("Sendmail process failure, check domain (\(domainName)) logging directory for an error entry with timestamp \(now)")

                // Error, grab all possible output and create a file with all error info

                let e = errpipe.fileHandleForReading.readDataToEndOfFile()
                let d = outpipe.fileHandleForReading.readDataToEndOfFile()

                let dump =
                """
                Process Termination Reason: \(process.terminationReason.rawValue)
                Sendmail exit status: \(process.terminationStatus)
                Details:
                - Sendmail Executable  : /usr/sbin/sendmail
                - Sendmail Options     : -t
                - Sendmail Timeout     : 10,000 mSec
                - Sendmail Error output: \(e.count) bytes
                - Sendmail Output      : \(d.count) bytes
                Below the output of sendmail is given in the following block format:
                (----- Email input -----)
                ...
                (----- Standard Error -----)
                ...
                (----- Standard Out -----)
                ...
                (----- End of output -----)

                (----- Email input -----)
                \(mail)
                (----- Standard Error -----)
                \(String(bytes: e, encoding: .utf8) ?? "")
                (----- Standard Out -----)
                \(String(bytes: d, encoding: .utf8) ?? "")
                (----- End of output -----)
                """

                let errorFileName = "sendmail-error-log-" + now
                if
                    let errorFileUrl = Urls.domainLoggingDir(for: domainName)?.appendingPathComponent(errorFileName).appendingPathExtension("txt"),
                    let dumpData = dump.data(using: .utf8),
                    ((try? dumpData.write(to: errorFileUrl)) != nil) {
                } else {
                    Log.atError?.log("Cannot create sendmail error file, content is: \n\(dump)\n")
                }
            }

        } catch let error {

            Log.atError?.log("Exception occured during sendmail execution, message = \(error.localizedDescription)")
        }
    }
}

应使用如下格式的字符串调用此例程:

let email: String =
    """
    To: \(emailAddress)
    From: \(fromAddress)
    Content-Type: text/html;
    Subject: Confirm Account Creation at \(domain.name)\n
    \(message)
    """

相关问题