diff --git a/preferences.html b/preferences.html
index 121f062..1bd279e 100644
--- a/preferences.html
+++ b/preferences.html
@@ -1537,6 +1537,15 @@ const PG_EXAMPLE_HTML_TPL = {
Fonction partagée à l'identique avec la page password-generator. Les
{{ placeholders }} sont substitués en dernier (valeurs échappées). ---- */
function emailEsc(s){ return String(s == null ? '' : s).replace(/[&<>]/g, c => ({'&':'&','<':'<','>':'>'}[c])); }
+/* URL sûre en attribut : whitelist de scheme + échappe les guillemets.
+ Neutralise javascript:, data:text/html, vbscript:… → « # » si scheme non autorisé.
+ (emailEsc a déjà neutralisé & < > ; il reste les " qui casseraient l'attribut.) */
+function emailUrl(u){
+ const s = String(u == null ? '' : u).trim();
+ const sch = /^([a-z][a-z0-9+.\-]*):/i.exec(s);
+ const ok = !sch || /^(https?|mailto|tel)$/i.test(sch[1]) || /^data:image\//i.test(s);
+ return (ok ? s : '#').replace(/"/g, '"');
+}
function emailFillVars(html, ctx){
return html.replace(/\{\{\s*(\w+)\s*\}\}/g, (m, k) => {
if(!(k in ctx)) return m;
@@ -1551,7 +1560,7 @@ function renderEmailHtml(src, ctx){
const inline = t => t
.replace(/`([^`]+)`/g, '$1')
.replace(/\*\*([^*]+)\*\*/g, '$1')
- .replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, '$1');
+ .replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (mm, txt, url) => '' + txt + '');
let html = '', i = 0, m;
while(i < lines.length){
const line = lines[i];
@@ -1559,18 +1568,18 @@ function renderEmailHtml(src, ctx){
const color = m[1] || '#5b9cf5', buf = [];
for(i++; i < lines.length && !/^:::\s*$/.test(lines[i]); i++) buf.push(lines[i]);
i++;
- html += '
' + buf.join('\n') + '';
+ html += ' |