Swift email verification
Verify emails in Swift with Verifly
Add a live email verification step to any Swift service with URLSession async/await and Codable. Verifly is an API-first, pay-as-you-go service — await a typed verdict, reject disposable or dead mailboxes, and keep the check server-side so your key never ships in an app.
import Foundation
struct Verdict: Codable {
let result: String
let is_valid: Bool
}
func verify(_ email: String) async throws -> Verdict {
var components = URLComponents(string: "https://verifly.email/api/v1/verify")!
components.queryItems = [URLQueryItem(name: "email", value: email)]
var request = URLRequest(url: components.url!)
request.setValue("Bearer vf_YOUR_KEY", forHTTPHeaderField: "Authorization")
let (data, _) = try await URLSession.shared.data(for: request)
return try JSONDecoder().decode(Verdict.self, from: data)
}Real-time SMTP mailbox checks
Single, batch, and async bulk verification
Disposable, role account, and catch-all detection
Pay-as-you-go credits with no subscription lock-in
Search fit
Built for Swift email verification
Use Verifly when you need a simple API, predictable pricing, and clean JSON results before emails hit your product, CRM, or campaign tool.
Email verification in Swift
Swift's modern concurrency makes an email check a one-liner to await, but the language cannot tell you whether a mailbox is real. A regex or NSDataDetector only confirms that user@dead-domain.com is shaped like an address; whether it accepts mail is a runtime fact behind an SMTP handshake. Verifly performs that handshake for you over one HTTPS request, and URLSession's async/await API turns the round-trip into a clean try await.
The idiomatic approach is URLSession.shared.data(for:) decoding into a Codable struct with JSONDecoder. Build the URL with URLComponents so the email is properly percent-encoded, set the Bearer header on a URLRequest, and await the response. The JSON carries a result field of deliverable, undeliverable, or risky plus boolean flags for disposable, role, catch_all, and smtp — all of which map onto Codable properties.
One important caution: keep the Bearer key server-side. If you call Verifly directly from an iOS or macOS app, that key can be extracted from the binary. Instead run verification in a server-side Swift context — a Vapor backend the app talks to — so the secret stays on your server. Pricing is pay-as-you-go from $2 per 1,000 checks down to $0.60 per 1,000 at volume, and you can self-register for 100 free credits with no card at the autonomous register endpoint.
Screen a signup in a Vapor route
The right home for the key is a server-side Swift app. In Vapor, your iOS client posts the address to your own route, and the route calls Verifly with the secret. Await the verdict, reject disposable and undeliverable addresses, and create the user only when the address passes. Wrap the call so a network error fails open — abort the signup only when Verifly positively reports a bad mailbox, not when it is briefly unreachable.
import Vapor
struct SignupInput: Content { let email: String }
struct Verdict: Content { let result: String; let disposable: Bool }
func routes(_ app: Application) throws {
app.post("signup") { req async throws -> HTTPStatus in
let input = try req.content.decode(SignupInput.self)
var headers = HTTPHeaders()
headers.bearerAuthorization = .init(token: Environment.get("VERIFLY_KEY")!)
let uri = URI(string: "https://verifly.email/api/v1/verify?email=\(input.email)")
let res = try await req.client.get(uri, headers: headers)
let v = try res.content.decode(Verdict.self)
guard v.result != "undeliverable", !v.disposable else {
throw Abort(.badRequest, reason: "Please use a valid, permanent email")
}
// try await User(email: input.email).save(on: req.db)
return .created
}
}Batch-verify a list in Swift
For cleaning many addresses, do not await the single endpoint in a loop — POST them together to /api/v1/verify/batch. It accepts a JSON body with an emails array and returns a results array in the same order, which decodes into an array of Codable items. Encode the request body with JSONEncoder, await one call, and filter the results down to deliverable addresses.
import Foundation
struct Item: Codable { let email: String; let result: String; let disposable: Bool? }
struct Batch: Codable { let results: [Item] }
func cleanList(_ emails: [String]) async throws -> [String] {
var request = URLRequest(url: URL(string: "https://verifly.email/api/v1/verify/batch")!)
request.httpMethod = "POST"
request.setValue("Bearer vf_YOUR_KEY", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(["emails": emails])
let (data, _) = try await URLSession.shared.data(for: request)
let batch = try JSONDecoder().decode(Batch.self, from: data)
return batch.results
.filter { $0.result == "deliverable" && !($0.disposable ?? false) }
.map { $0.email }
}FAQ
Frequently asked questions
Can I call Verifly directly from an iOS app?
You should not. The Bearer key can be extracted from a shipped binary. Keep verification server-side — run it in a Vapor backend that your app talks to — so the key stays a secret on your server rather than in the App Store bundle.
How do I decode the response in Swift?
Define a Codable struct with the fields you need — result: String, is_valid: Bool, and optional disposable/role/catch_all/smtp — and decode with JSONDecoder. URLSession's data(for:) async method gives you the Data to decode in one try await.
How do I percent-encode the email in the query?
Build the URL with URLComponents and set queryItems to [URLQueryItem(name: "email", value: email)]. URLComponents encodes the value for you, so a plus sign or unusual character in the address does not break the request.
How do I batch-verify a list of addresses?
POST them to /api/v1/verify/batch with a JSON emails array — encode ["emails": emails] with JSONEncoder — and decode the results array into an array of Codable items, then filter on result. Batching beats awaiting the single endpoint per address.
How do I stop a network error from blocking signup?
Fail open: only reject when Verifly positively returns undeliverable or disposable. Wrap the call so a thrown URLError or timeout lets the registration proceed rather than turning a real user away on a transient blip.
What does Swift email verification cost?
Pricing is pay-as-you-go from $2 per 1,000 checks down to $0.60 per 1,000 at volume, with 100 free credits when you self-register. There is no subscription. For AI agents, Verifly also exposes an MCP server at verifly.email/mcp.