Пожалуй, через cron - это не единственный, но самый разумный вариант.
Крон задачу можете запускать хоть каждую минуту.
Правильный скрипт не будет создавать большой нагрузки.
Будет искать именно те заказы, где письмо ещё не отправлено, а по времени прошло более 20 минут (и менее суток, наверно).
Если рассматривать в качестве альтернативы - задержку в скрипте (нечто вроде sleep) на 20 минут - это совсем не рациональное решение.