Asynchronous sendHTMLEmail Not Working

I am working on a project and using the sendHTMLEmail for error handling. I’ve been attempting to use the Asynchronous version and am not having any success. I do not get a success or error call. At times an email will be sent but the completion handler does not work. If I use the Synchronous version all works as expected. I have verified that sendErrorCodeEmail() is being called. Any help would be appreciated.


func sendErrorCodeEmail(_ errorCode: String)
    {
        // Asynchronous Version
        let subject = "FLO Error Called"
        let body = "\(errorCode)"
        let recipient = ["jon@flocycling.com"]
        
        self.backendless?.messagingService.sendHTMLEmail(subject, body: body, to: recipient, response: { (response : Any?) -> Void in
            
            print("The error code email was sent successfully. \(response)")
            
        }, error:  { (fault : Fault?) -> () in
            
            print("The server reported a fault in the sendErrorCode emial: \(fault)")
            
        })
    }

I’ve been working on this issue and cannot make much sense of it. Here is what I’ve found today.

  1. If I place the Async method in my initial ViewController it works as expected. Here is a stripped down version of that VC.
import UIKit
import CoreData
import MessageUI
import FBSDKLoginKit


class HomeViewController: UIViewController, FLODataHandlerDelegate, MFMailComposeViewControllerDelegate
{
    // Backendless Access
    let backendless = Backendless.sharedInstance()
    
    override func viewDidLoad()
    {
        super.viewDidLoad()


        self.sendErrorCodeEmail("Test")
    }


    func sendErrorCodeEmail(_ errorCode: String)
    {
        // Asynchronous Version
        let subject = "FLO Error Called"
        let body = "\(errorCode)"
        let recipient = ["jon@hotmail.com"]
        
        self.backendless?.messagingService.sendHTMLEmail(subject, body: body, to: recipient, response: { (response : Any?) -> () in
            
            print("The error code email was sent successfully. \(response)")
            
        }, error:  { (fault : Fault?) -> () in
            
            print("The server reported a fault in the sendErrorCode email: \(fault)")
        })
    }
}
  1. When I move the method to a delegate class it does not work. Here is the delegate class.
import Foundation


protocol FLOSessionHandlerDelegate
{
    func floSessionHandlerDidFinishLoading(_ sessionHandler : FLOSessionHandler) -> ()
    func floSessionHandlerDidFail(_ sessionHandler : FLOSessionHandler, errorMessage: String) -> ()
}


class FLOSessionHandler : NSObject
{
    //Properties
    var sessionURL : URL?
    var sessionData : Data? = nil
    var session : URLSession?
    
    // Delegate Property
    var delegate : FLOSessionHandlerDelegate?
    
    // Backendless Access
    let backendless = Backendless.sharedInstance()


    // Init Methods
    init(url : URL, delegateInput: FLOSessionHandlerDelegate)
    {
        self.sessionURL = url
        self.delegate = delegateInput
    }


    // Class Methds
    func startSession()
    {
        // Start the connection with the URL that was passed in the unit method in the dataHandler.
        self.session = URLSession.shared
        let dataTask = self.session!.dataTask(with: self.sessionURL!, completionHandler: { (data, response, error) -> Void in
           
            if error == nil
            {
                if data != nil
                {                    
                    self.sessionData = data
                                        
                    // Let the delegate method in FLODataHander know that the FLOConnectionHandler is done.
                    self.delegate?.floSessionHandlerDidFinishLoading(self)
                }
                else
                {
                    print("I am in the FLOSessionHanlder - There is no data")
                }
            }
            else if error != nil
            {                    
                // Create an error message that is sent to FLO showing the problem url and the associated error message.
                let errorMessage = (error?.localizedDescription)! as String
                let url = self.sessionURL! as URL
                let errorCodeMessage = "There is an error in FLOSessionHandler's startSession().  The URL with the issue is: \(url) and the error has the following error message: \(errorMessage)"
                
                self.sendErrorCodeEmail(errorCodeMessage)                
            }
        })
        
        dataTask.resume()
    }
    
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    func sendErrorCodeEmail(_ errorCode: String)
    {        
        print("Is this getting called?")
        
        // Asynchronous Version
        let subject = "FLO Error Called"
        let body = "\(errorCode)"
        let recipient = ["jon@hotmail.com"]
        
        self.backendless?.messagingService.sendHTMLEmail(subject, body: body, to: recipient, response: { (response : Any?) -> () in
            
            print("The error code email was sent successfully. \(response)")
                   
        }, error:  { (fault : Fault?) -> () in
            
            print("The server reported a fault in the sendErrorCode email: \(fault)")
        })
    }
}

I have confirmed that sendErrorCodeEmail() is called but sendHTMLEmail does nothing. Any help would be appreciated.

Hi Jon,

Thanks for the report, I’ve created an internal ticket with ID BKNDLSS-14057 to investigate this issue. Our iOS specialist may contact you here soon if we need any additional details.

Thanks Olga. I’ve checked the delegate. The class is inheriting from NSObject.

Take care,

Jon

Hi, Jon.
I’ve simplified your code and checked. This code works fine. Can you please show the calling of init and start session methods?

Regards, Olga

class FLOSessionHandler: NSObject { 
 // Delegate Property 
 var delegate : FLOSessionHandlerDelegate? 
 // Backendless Access 
 let backendless = Backendless.sharedInstance() 
 // Init Methods 
 init(delegateInput: FLOSessionHandlerDelegate) { 
 self.delegate = delegateInput 
 } 
 
 // Class Methds 
 func startSession() { 
 // Create an error message that is sent to FLO showing the problem url and the associated error message. 
 let errorCodeMessage = "ERROR MESSAGE" 
 self.sendErrorCodeEmail(errorCodeMessage) 
 } 
 
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 
 func sendErrorCodeEmail(_ errorCode: String) { 
 
 let backendless = Backendless .sharedInstance() 
 backendless?.initApp("XXX", 
 secret: "XXX", 
 version: "v1") 
 
 print("Is this getting called?") 
 // Asynchronous Version 
 let subject = "FLO Error Called" 
 let body = "\(errorCode)" 
 let recipient = ["XXX@XXX.XXX"] 
 backendless?.messagingService.sendHTMLEmail(subject, 
 body: body, 
 to: recipient, 
 response: { (response : Any?) -> () in 
 print("The error code email was sent successfully. \(response)") 
 }, 
 error: { (fault : Fault?) -> () in 
 print("The server reported a fault in the sendErrorCode email: \(fault)") 
 }) 
 } 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}


The code below is in a class that conforms to the FLOSessionHandlerDelegate. In this class I call the init() and startSession() methods. Please see below.

    func startSessionHandler()
    {
        let blogURL = URL(string: self.URLDictionary["FLO Cycling"]!)
        self.sessionHandler = FLOSessionHandler(url: blogURL!, delegateInput: self)
        self.sessionHandler!.startSession()
    }

Please, check this one.
Regards, Olga

 func startSession() 
 
 { 
 
 // Start the connection with the URL that was passed in the unit method in the dataHandler. 
 
 self.session = URLSession.shared 
 
 let dataTask = self.session?.dataTask(with: self.sessionURL!) { 
 
 (data, response, error) in 
 
 
 
 if error == nil { 
 
 if data != nil { 
 
 self.sessionData = data 
 
 // Let the delegate method in FLODataHander know that the FLOConnectionHandler is done. 
 
 self.delegate?.floSessionHandlerDidFinishLoading(self) 
 
 } 
 
 else { 
 
 print("I am in the FLOSessionHanlder - There is no data") 
 
 } 
 
 } 
 
 
 
 else if error != nil { 
 
 //Create an error message that is sent to FLO showing the problem url and the associated error message. 
 
 let errorMessage = (error?.localizedDescription)! as String 
 
 let url = self.sessionURL! as URL 
 
 let errorCodeMessage = "There is an error in FLOSessionHandler's startSession(). The URL with the issue is: \(url) and the error has the following error message: \(errorMessage)" 
 
 self.sendErrorCodeEmail(errorCodeMessage) 
 
 } 
 
 } 
 
 dataTask?.resume() 
 
 } 



I tried this method and I am still having the same issue. If you would like, I can send the project to you to investigate. I’m stumped.

Did you run Olga’s code verbatim? Exactly the same function?

I’ve attached a sample project that shows the issue. You will find a ViewController that sets up the NSSession Delegate class. A few notes.

ViewController

  1. There are two URLs up top. One is called goodURL and the other is badURL. If you change the URL in the init() in setUpSendErrorCodeEmailTest() you will see the delegate call back work for the good URL but not the bad URL.

  2. When badURL is used, sendErrorCodeEmail() is called in the delegate SendErrorCodeEmailTest when the session has an error. The delegate callback for sessionFailed is never called since the completion handler for sendHTMLEmail is not called.

I hope this helps define the problem.

FacebookLoginWithBackendless.zip (20.22MB)

Yes, I did. I copied her code in the sample project I attached.

Jon,

We do not review user code as can drastically reduce support productivity (imagine every one sending us a project to review and debug).

Please try creating an ultra simple program which does nothing but uses the sendHTMLEmail function. If that does not work, we can review that. In other words, the problem needs to be scoped to include only Backendless API.

Regards,
Mark

I created a method that calls the sendHTMLEmail method directly in the delegate and it works.

func callSendHTMLEmail()
    {
        let errorCodeMessage = "There is an error."
        self.sendErrorCodeEmail(errorCodeMessage)
    }
    
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    func sendErrorCodeEmail(_ errorCode: String)
    {        
        // Asynchronous Version
        let subject = "Error Called"
        let body = "\(errorCode)"
        let recipient = ["xx@xx.com"]
        
        self.backendless?.messagingService.sendHTMLEmail(subject, body: body, to: recipient, response: { (response : Any?) -> () in
            
            print("The error code email was sent successfully. \(response)")
            let errorMessage = "This is complete"
            self.delegate?.sessionFailed(self, errorMessage: errorMessage)
            
        }, error:  { (fault : Fault?) -> () in
            
            print("The server reported a fault in the sendErrorCode email: \(fault)")
        })
    }

When sendErrorCodeEmail() is called from code Olga provided or my code, sendHTMLEmail does not work. I have no idea why.

Olga was working off of your code and modified it (which is not something our support staff is supposed to do and I will discuss it with her).

My suggestion is to take the code that works and start expanding it with your code to see at what point it stops working as expected.

Regards,
Mark

Thanks Mark.

If anyone is reading this, I figured out what was happening. It is not a Backendless issue. It has to do with threading. If sendErrorCodeEmail() is called on the main thread, the program works as expected. To do this the add the following code.

DispatchQueue.main.async{
    sendErrorCodeEmail()
}