un1t: Да, вы правы. Дополнительное условие тут не учёл. Тогда придётся раскорячиваться и сначала мержить с LEFT JOIN, а потом уже фильтровать результат по условию t1.name=t2.name. Увы, это не SQL, тут вот такие дополнительные приседания нужны.
Смотрю на код и не могу понять - где именно оно должно генерироваться? К random.randint() претензий нет - всегда работает как надо. Уточните. пожалуйста, свой вопрос.
На стороне фронтенда - тоже совсем-совсем без фреймоврков? Если да, то я вам не завидую, если можно хотя бы jQuery - то это облегчит жизнь. Вот как там делаются POST-запросы: https://api.jquery.com/jquery.post/
Ресурсов - это гигагерц, ядер и памяти? Торнадо работает на одном ядре и если ядер несколько - можно задействовать их, применяя multiprocessing или обёртку над ним - joblib.
Если ядро позволено применять категорически только одно и парсинг реально будет нужен 2-3 раза в день - городите асинхронные корутины, делайте всё "внутри".
Перед вот этой строчкой
token = generate_confirmation_token(user.email)
напишите
Или поясните, что это за объект, откуда он берётся и прочее