Открытое сокетное соединение с SMTP-сервером с помощью Stream в Swift 3

Мне нужно подключиться к SMTP-серверу и при неудачном открытии соединения. Неудачное рукопожатие (отсутствие аутентификации) - это самое дальнее, что я получил здесь. Я открываю сокет для обычного сервера, но не могу сделать это здесь, чтобы отправить электронное письмо.

    private func connect() throws {
        var input: InputStream? = nil
        var output: OutputStream? = nil

        Stream.getStreamsToHost(withName: server, port: port, inputStream: &input, outputStream: &output)

        guard let inputSafe = input, let outputSafe = output else {
            throw FailerError.unableToConnectToHost
        }

        self.inputStream = inputSafe
        self.outputStream = outputSafe

        // TODO: Authentication using login

        // Enable SSL/TLS on the streams
//        inputStream!.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySocketSecurityLevel as String))
//        outputStream!.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySocketSecurityLevel as String))
//        
//        // Define custom SSL/TLS settings
//        let sslSettings: [NSString : Any] = [
//             NSStream automatically sets up the socket, the streams and creates a trust object and evaulates it before you even get a chance to check the trust yourself. Only proper SSL certificates will work with this method. If you have a self signed certificate like I do, you need to disable the trust check here and evaulate the trust against your custom root CA yourself.
//            NSString(format: kCFStreamSSLValidatesCertificateChain): kCFBooleanFalse,
//            //
//            NSString(format: kCFStreamSSLPeerName): kCFNull,
//            // We are an SSL/TLS client, not a server
//            NSString(format: kCFStreamSSLIsServer): kCFBooleanFalse,
//            
//            NSString(format: kCFStreamSocketSecurityLevelNegotiatedSSL): kCFBooleanTrue
//        ]
//        
//        // Set the SSL/TLS settingson the streams
//        inputStream!.setProperty(sslSettings, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySSLSettings as String))
//        outputStream!.setProperty(sslSettings, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySSLSettings as String))


        inputStream.delegate = self
        outputStream.delegate = self

        inputStream.schedule(in: .main, forMode: .commonModes)
        outputStream.schedule(in: .main, forMode: .commonModes)

        inputStream.open()
        outputStream.open()
    }

В комментируемой части я пытаюсь установить некоторые вещи, но на самом деле не знаю, что там должно быть. Любые идеи, кто-нибудь, пожалуйста?

Просто чтобы уточнить, это для плохо спроектированного API, который использует SMTP для получения данных (не моя идея, но я должен его использовать), поэтому, пожалуйста, не предлагайте MessageUI, иначе приложение будет отклонено из-за прямой отправки электронной почты:)

Если вам это интересно, вы можете ознакомиться со всей информацией об игровой площадке: https://gist.github.com/rafiki270/c004b92deca437934f702efd3508bd83

1 ответ

Решение

@Ondrej В документации Apple "Введение в потоковое руководство по программированию для какао" упоминается, что класс NSStream ( Objective C) / Stream (Swift) не поддерживает подключение к удаленному хосту на iOS. Ваш альтернативный вариант - использовать CFStream, воспользовавшись бесплатным мостом между CFStream и NSStream для приведения ваших CFStreams к NSStreams.

Ниже приведен пример того, как вы делаете это с CFStream.

CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 80, &readStream, &writeStream);

NSInputStream *inputStream = (__bridge_transfer NSInputStream *)readStream;
NSOutputStream *outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];

Надеюсь это поможет.

Другие вопросы по тегам