AWS Messaging & Targeting Blog
How to handle a "Throttling – Maximum sending rate exceeded" error
Calls to Amazon SES are limited by the account’s maximum send rate. When you call Amazon SES faster than your maximum allocated send rate, Amazon SES will reject your over the limit requests with a “Throttling – Maximum sending rate exceeded” error. Depending on which Amazon SES interface you call, the error is passed back to you differently:
- With the Amazon SES HTTP Query interface the error will be received as a “Throttling” error response with a “Maximum sending rate exceeded.” message.
- With the SMTP interface, Amazon SES responds with “454 Throttling failure: Maximum sending rate exceeded” after the DATA command.
Developer Guide.
AmazonSimpleEmailServiceClient client = new AmazonSimpleEmailServiceClient( new BasicAWSCredentials( "ACCESS_KEY", //replace with your access key "SECRET_KEY" //replace with your secret key )); //initialize a RateLimiter that will limit your requests rate to 2 requests per second RateLimiter rateLimiter = RateLimiter.create(2); List destinations = Arrays.asList("EMAIL_ADDRESS_1", "EMAIL_ADDRESS_2", "EMAIL_ADDRESS_3"); //replace with your TO email addresses for (String destination : destinations) { int maxRetries = 10; while(maxRetries-->0) { try { SendEmailRequest request = new SendEmailRequest() .withSource("SOURCE_EMAIL_ADDRESS"); //replace with your FROM email address //wait for a permit to become available rateLimiter.acquire(); //call Amazon SES to send the message SendEmailResult result = client.sendEmail(request); System.out.println("sent "+result.getMessageId()); break; } catch (AmazonServiceException e) { //retries only throttling errors if ("Throttling".equals(e.getErrorCode() && "Maximum sending rate exceeded.".equals(e.getMessage())) { System.out.println("Maximum send rate exceeded when sending email to "+destination+". " +(maxRetries>1?"Will retry.":"Will not retry.") ); } else { System.out.println("Unable to send email to: "+destination+". " +e.toString()); break; } } catch(Exception e) { System.out.println("Unable to send email to: "+destination+". " +e.toString()); break; } } }
exponential backoff“. With exponential backoff, you exponentially increase the backoff duration on each consecutive failure. The following Java snippet shows a simple implementation of the exponential backoff algorithm and how to use it to call Amazon SES.
public static long getSleepDuration(int currentTry, long minSleepMillis, long maxSleepMillis) { currentTry = Math.max(0, currentTry); long currentSleepMillis = (long) (minSleepMillis*Math.pow(2, currentTry)); return Math.min(currentSleepMillis, maxSleepMillis); }
AmazonSimpleEmailServiceClient client = new AmazonSimpleEmailServiceClient( new BasicAWSCredentials( "ACCESS_KEY", //replace with your access key "SECRET_KEY" //replace with your secret key )); List destinations = Arrays.asList("EMAIL_ADDRESS_1", "EMAIL_ADDRESS_2", "EMAIL_ADDRESS_3"); //replace with your TO email addresses for (String destination : destinations) { SendEmailRequest request = new SendEmailRequest() .withSource("SOURCE_EMAIL_ADDRESS"); //replace with your FROM email address int currentTry = 0; int maxRetries = 10; while(maxRetries-- > 0) { try { currentTry++; //call Amazon SES to send the message SendEmailResult result = client.sendEmail(request); System.out.println("sent "+result.getMessageId()); break; } catch (AmazonServiceException e) { //retries only throttling errors if ("Throttling".equals(e.getErrorCode()) && "Maximum sending rate exceeded.".equals(e.getMessage())) { long backoffDuration = getSleepDuration(currentTry, 10, 5000); System.out.println("Maximum send rate exceeded when sending email to "+destination+". " +(maxRetries>1?"Will retry after backoff.":"Will not retry after backoff.") ); try { Thread.sleep(backoffDuration); } catch (InterruptedException e1) { return; } } else { System.out.println("Unable to send email to: "+destination+". " +e.toString()); break; } } catch(Exception e) { System.out.println("Unable to send email to: "+destination+". " +e.toString()); break; } } }