Самый простой способ, который я могу придумать, - это отложить отправку каждого письма в зависимости от того, сколько их ожидают.
final ScheduledThreadPoolExecutor service = new ScheduledThreadPoolExecutor(1);
int ratePerSecond = ...
public static void execute(Runnable run) {
int delay = 1000 * service.getQueue().size() / ratePerSecond;
service.schedule(run, delay, TimeUnit.MILLISECONDS);
}
Это обеспечит выполнение задач настолько близко друг к другу, насколько позволяет скорость.