Esta técnica une la tabla contra sí misma en una subconsulta, pero solo coincide con una fila (según contact_id y coincidencia de correo electrónico. El truco es que la subconsulta devuelve solo una de las direcciones de correo electrónico usando MIN, teóricamente la primera en orden alfabético (no es confiable, pero dijiste que no importaba).
He probado esto con buenos resultados.
UPDATE
email
JOIN (SELECT contact_id, MIN(email) as email
FROM email GROUP BY contact_id) as singles
USING(contact_id, email)
set is_primary=1;