Why SMTP Basic Authentication is Dead (And What to Use Instead)

Microsoft is finally pulling the plug on SMTP basic authentication in Exchange Online, and if you're still using app passwords to send automated emails, it's time to migrate. Here's why this change is actually good news for security, and how Azure Communication Services provides a better alternative.
Exchange Online to retire Basic auth for Client Submission (SMTP AUTH) | Microsoft Community Hub
The Fatal Flaw of SMTP Basic Auth
SMTP basic authentication has a fundamental security problem: it uses static credentials that grant full mailbox access.
When your application authenticates with a username and password to send emails, that credential can:
- Read all emails in the mailbox
- Delete messages
- Send emails as that user
- Access calendars and contacts
- Potentially access SharePoint and Teams via the same credential
This violates the principle of least privilege. Your notification service doesn't need to read emails or access calendars - it just needs to send outbound messages. But SMTP basic auth gives it everything.
Real-World Attack Scenario
Imagine your WordPress site uses an app password to send password reset emails. An attacker who compromises your server now has:
- Full access to that mailbox
- Ability to intercept sensitive emails
- Credentials that won't expire unless manually revoked
- A foothold for lateral movement in your organization
With basic auth going away, Microsoft is forcing everyone to adopt better security patterns.
What Happened to SendGrid?
SendGrid, once the go-to solution for developers with its generous 100 emails/day free tier, was acquired by Twilio in 2019. In 2024, Twilio eliminated the free tier entirely and restructured pricing to focus on enterprise customers. The new entry-level plan starts at $19.95/month for 50,000 emails, but comes with a catch: you're also paying for Twilio's marketing features whether you need them or not.
For simple transactional email (password resets, notifications, receipts), this pricing shift pushed many developers to reconsider their options. A small SaaS app sending 5,000 notifications per month now faces a $240/year minimum with SendGrid, compared to just $15/year with Azure Communication Services ($0.00025 × 5,000 × 12 months).
The acquisition also introduced complexity - what was once a straightforward SMTP relay service is now bundled with marketing automation, A/B testing, and analytics tools that most developers don't need for basic transactional email. SendGrid still works well for high-volume senders and marketing campaigns, but for developers who just need reliable email delivery without the bloat, Azure Communication Services offers a leaner, more cost-effective alternative that scales precisely with your actual usage.
This pricing change, combined with Microsoft's deprecation of SMTP basic auth, created the perfect storm that's driving the current migration wave toward modern email APIs.
Enter Azure Communication Services Email
Azure Communication Services takes a different approach: it separates email sending from mailbox access entirely. You don't need a licensed Exchange mailbox - just a verified domain and an API endpoint.
Security Advantages
1. No Mailbox to Compromise Your sending domain exists purely for outbound email. There's no inbox, no calendar, no data to steal.
2. Scoped Permissions API keys or managed identities can only send email - nothing else. An attacker who steals your connection string gets limited capabilities, not full tenant access.
3. Token-Based Authentication Connection strings can be rotated. Managed identities eliminate secrets entirely. OAuth tokens expire automatically.
4. Audit Trail Every email send is logged in Azure Monitor. You get visibility into who sent what, when.
5. No Credential Stuffing Risk There are no user credentials to steal or reuse across services.
Cost Comparison
Exchange Online SMTP:
- Requires licensed mailbox: €4-20/month per mailbox
- Annual cost: €48-240/year minimum
Azure Communication Services:
- Pay per email: $0.00025 per message
- 10,000 emails/month: $2.50/month
- 100,000 emails/month: $25/month
For most automated sending scenarios, ACS is significantly cheaper.
Provisioning Script
Here's a complete script to set up Azure Communication Services Email:
#!/bin/bash # Configuration RESOURCE_GROUP="email-services-rg" LOCATION="global" EMAIL_SERVICE_NAME="mycompany-email" ACS_NAME="mycompany-comms" DOMAIN_NAME="yourdomain.com" # Create resource group az group create \ --name $RESOURCE_GROUP \ --location westeurope # Create Email Communication Service az resource create \ --resource-group $RESOURCE_GROUP \ --name $EMAIL_SERVICE_NAME \ --resource-type "Microsoft.Communication/emailServices" \ --properties '{"dataLocation":"Europe"}' \ --location global # Create Communication Services resource az communication create \ --name $ACS_NAME \ --resource-group $RESOURCE_GROUP \ --data-location Europe \ --location global # Add custom domain to email service az resource create \ --resource-group $RESOURCE_GROUP \ --name "$EMAIL_SERVICE_NAME/$DOMAIN_NAME" \ --resource-type "Microsoft.Communication/emailServices/domains" \ --properties '{"domainManagement":"CustomerManaged"}' \ --location global # Get DNS records for domain verification echo "Add these DNS records to verify your domain:" az resource show \ --ids "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Communication/EmailServices/$EMAIL_SERVICE_NAME/domains/$DOMAIN_NAME" \ --query "properties.verificationRecords" -o json # Get connection string (after domain is verified) az communication list-key \ --name $ACS_NAME \ --resource-group $RESOURCE_GROUP \ --query primaryConnectionString -o tsv echo "" echo "Next steps:" echo "1. Add the DNS records shown above to $DOMAIN_NAME" echo "2. Wait 5-30 minutes for verification" echo "3. Connect domain in Azure Portal: $ACS_NAME -> Email -> Connect domain" echo "4. Use the connection string above in your application"
Sending Email with curl
Once your domain is verified and connected, sending email is straightforward:
#!/bin/bash # Your ACS endpoint and key ENDPOINT="https://your-acs-name.communication.azure.com" CONNECTION_STRING="endpoint=https://...;accesskey=..." # Extract access key from connection string ACCESS_KEY=$(echo $CONNECTION_STRING | sed -n 's/.*accesskey=\([^;]*\).*/\1/p') # Email payload read -r -d '' PAYLOAD <<'EOF' { "senderAddress": "noreply@yourdomain.com", "recipients": { "to": [ { "address": "recipient@example.com", "displayName": "Recipient Name" } ] }, "content": { "subject": "Migration from SMTP Basic Auth Complete", "plainText": "Your email service has been successfully migrated to Azure Communication Services.", "html": "<html><body><h1>Success!</h1><p>Your email service has been successfully migrated to Azure Communication Services.</p><p>This email was sent securely without SMTP basic authentication.</p></body></html>" } } EOF # Send email curl -X POST "$ENDPOINT/emails:send?api-version=2023-03-31" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $ACCESS_KEY" \ -d "$PAYLOAD" echo "" echo "Email sent successfully"
PowerShell Alternative
$endpoint = "https://your-acs-name.communication.azure.com" $accessKey = "your-access-key" $body = @{ senderAddress = "noreply@yourdomain.com" recipients = @{ to = @( @{ address = "recipient@example.com" displayName = "Recipient Name" } ) } content = @{ subject = "Test Email" plainText = "This is a test email from Azure Communication Services" html = "<h1>Test</h1><p>This is a test email</p>" } } | ConvertTo-Json -Depth 10 $headers = @{ "Content-Type" = "application/json" "Authorization" = "Bearer $accessKey" } Invoke-RestMethod ` -Uri "$endpoint/emails:send?api-version=2023-03-31" ` -Method POST ` -Headers $headers ` -Body $body
Migration Checklist
If you're currently using SMTP basic auth, here's your migration path:
- Audit all applications using SMTP authentication
- Provision Azure Communication Services Email
- Verify your sending domain(s) with DNS records
- Update applications to use ACS REST API
- Test email delivery and formatting
- Monitor for 30 days to catch edge cases
- Disable SMTP authentication on old mailboxes
- Decommission service account mailboxes (save license costs)
Using Managed Identity (Zero Secrets)
For production workloads in Azure, use Managed Identity instead of connection strings:
// C# example with Azure.Identity using Azure.Communication.Email; using Azure.Identity; var endpoint = new Uri("https://your-acs-name.communication.azure.com"); var credential = new DefaultAzureCredential(); var emailClient = new EmailClient(endpoint, credential); var emailMessage = new EmailMessage( senderAddress: "noreply@yourdomain.com", recipientAddress: "user@example.com", content: new EmailContent("Subject") { PlainText = "Body text", Html = "<h1>Body HTML</h1>" }); await emailClient.SendAsync(emailMessage);
Grant your application's managed identity the "Contributor" role on the Communication Services resource, and you're done - no secrets to manage.
Conclusion
The death of SMTP basic authentication isn't just a compliance burden - it's an opportunity to adopt a more secure, cost-effective email solution. Azure Communication Services provides:
- Better security through scoped permissions and token-based auth
- Lower cost with pay-per-use pricing
- Better deliverability with dedicated infrastructure
- Modern APIs instead of decades-old SMTP protocol
The migration might seem daunting, but the scripts above get you 80% of the way there. The remaining 20% is updating your application code to call a REST API instead of connecting to an SMTP server - a change most developers can complete in an afternoon.
Start your migration today, before Microsoft forces your hand by disabling basic auth tenant-wide.
Resources:
