이전에 한번 정리했지만, SMTP를 활용하고자 했다. [링크]
이유는 중복 이메일과 가계정을 거를 수 없었기 때문인데, 이메일 형식만 맞추면 되었기에 발생하는 문제점이었다.
이를 해결하고자 유저 이메일 주소로 인증 번호를 발송하고, 작성한 번호가 일치하는지 구성하여
1) 이메일이 존재하는지, 2)중복 이메일을 거를 수 있지 않을까 싶었다.
[12.08]
SMTP로 인증번호를 발송이 된다.
알고보니 그동안 안되던 이유는 사용하는 hostSMTP 때문이었다.
몰랐는데, gmail은 2022년부로 로그인 보안 수준이 낮은 앱의 접근을 지원 중단했었다고 한다.
(기존에는 이메일 같은 SMTP를 발송할 때, 앱 자체가 구글 계정에 아이디와 비밀번호만으로 접근할 수 있도록 지원했었는데, 이게 중단된 것이었다.)
자세한 내용이 궁금하면 아래를 참고!
SMTP 코드를 적용하기 위해 여러 차례 도전을 했는데, 그동안 여러 문제가 발생했었다.
그 중, 발송 직전까지 갔으나 어떠한 이유로 발송되지 않던 Username and Password not Accepted 관련 이슈를 먼저 정리한다.
인증번호 코드는 잘 생성된다.
하지만 위처럼 Username과 Password가 허가되지 않는 상황이 반복적으로 발생했다.
라이브러리를 만든 사람의 리드미를 따라 구성했음에도 작동되지 않아 무엇이 문제인지 이해조차 하지 못했는데, 더 파다보니 원인을 찾았다.
Google에서 "Less Secure Apps Option"을 2022년 5월부로 중단했다. [참고]
알고보니 SMTP는 한 계정의 이메일 주소와 비밀번호를 활용해서 이메일을 발송했는데,
이 방식이 보안 수준이 낮은 앱 으로 구분되고 있었다는 점이다.
좀 더 찾아보니 구글이 보안 수준이 낮은 앱을 제한하기 시작한 이유는 단순히 이메일과 비밀번호만으로 접근하는 기능을 제공하는 어플 / 기능은 계정이나 기기가 유출될 가능성을 높이기 때문이라고 한다. [참고]
이로 인해 SMTP 라이브러리는 더이상 쓰지 못하는 것으로 이해하게 되었는데,
나름 대응하는 방법이 찾아보니 4가지 정도로 추려진다.
1. 구글이 아닌 네이버 이메일을 생성 활용
2. 인증번호 없이 Firebase에서 제공하는 authenticate 함수 활용
3. 2차 인증 번호로 비밀번호 대체 (2fa)
4. Xoauth 2 활용
일단 1번은 제외하기로 했다.
이메일 발송하는 이유가 단순히 인증번호 발송도 있지만, 하나의 계정에서 모든 처리를 하고 싶기 때문.
2번도 제외하고자 하는데, 정말 간단하다.
기초적인 인증 방식은 예전부터 구현할 수 있었는데 굳이 이제와서 되돌아가고 싶지 않았다.
(적어도 끝까지 한번 해보고 돌아가던지 해야지!)
4번은 개인적으로 이해가 되지 않아 일단 3번 방법을 진행해보고자 했다.
별도로 hostSMTP를 네이버로 변경하게 되면 이전 방식처럼 이메일 주소와 비밀번호만으로 발송이 가능한 것으로 보였다.
하지만 애초에 목적이 기존 어플 계정에서 발송하는 인증번호였기에 네이버로 이메일 주소를 변경하는 방안도 퇴출!
다행히 2차 인증번호는 참고 영상을 통해 적용할 수 있게 되었다. 영상링크
(생각보다 내용이 많아서 2차 인증번호에 대해서도 간단하게 정리를 따로 해봐야겠다).
이해하기로는 2차 인증번호를 활성화하면 계정에 접근을 할 때마다 2차 인증 비밀번호를 입력해야한다고 한다.
다행히 자체적으로 심어두면 문제는 없어지는 것 같다.
Google 2nd access 비밀번호를 설정하게 되면서 무사히 코드가 보내지는 것을 확인했다.
여기서 또 다른 문제가 발생하는데, 코드 내에서 Main과 Global Thread 관련해서 이슈가 발생했다.
안내 메시지가 등장하도록 구성하였는데, UI를 변경하게 되면서 Main Thread를 사용하도록 했다.
여기서 몰랐던 부분은 SMTP에서 사용하는 SSLHandShake라고 하는 친구는 Main thread에서 사용되면 안된다고 한다.
찾아볼 내용이 하나 더 늘었따!
우선은 아래처럼 smtpManager는 global에서,
UI는 Main에서 작동할 수 있도록 적용하였다.
private func sendEmailToSMTP() {
guard let email = registrationView.emailTfView.textfield.text else { return }
DispatchQueue.global().async {
self.smtpManager.sendAuth(userEmail: email) { [weak self] (authCode, success) in
guard let self = self else { return }
if success {
DispatchQueue.main.async {
self.showAlert(type: .checkEmail)
print(authCode)
}
} else {
DispatchQueue.main.async {
self.showAlert(type: .checkEmail)
print("이건 문제??", authCode)
}
}
}
}
}
문제없이 이메일이 잘 들어오고 있다!