diff --git a/web/src/components/admin/AdminEmail.jsx b/web/src/components/admin/AdminEmail.jsx index 5d7cd6d..a33a467 100644 --- a/web/src/components/admin/AdminEmail.jsx +++ b/web/src/components/admin/AdminEmail.jsx @@ -1,6 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import { api } from '../../lib/api.js'; import { copyRichEmail } from '../../lib/emailClipboard.js'; +import { downloadOutlookDraft } from '../../lib/outlookDraft.js'; const INITIAL = { subject: 'Actualités du Business Club SLUC Nancy', @@ -65,6 +66,16 @@ export function EmailCreatorTab() { } }; + const downloadOutlook = () => { + const slug = form.subject.normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-|-$/g, '').toLowerCase() || 'email'; + downloadOutlookDraft({ + subject: form.subject, + html: data.html, + filename: `${slug}-outlook.eml`, + }); + flash('outlook'); + }; + const download = () => { const blob = new Blob([data.html], { type: 'text/html' }); const url = URL.createObjectURL(blob); @@ -115,12 +126,13 @@ export function EmailCreatorTab() { {error &&

{error}

}
- + +

- Dans un brouillon Outlook, utilisez Ctrl + clic pour tester un lien. Après envoi, un clic normal suffit. + Pour Outlook, ouvrez le fichier .eml téléchargé : le mail est chargé comme un vrai brouillon HTML, sans collage ni remplacement des styles. Dans le brouillon, utilisez Ctrl + clic pour tester un lien.

diff --git a/web/src/components/admin/AdminTabs.jsx b/web/src/components/admin/AdminTabs.jsx index 4cecb7b..0840912 100644 --- a/web/src/components/admin/AdminTabs.jsx +++ b/web/src/components/admin/AdminTabs.jsx @@ -1,6 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import { api, dateParts, seasonLabel, statutLabel } from '../../lib/api.js'; import { copyRichEmail } from '../../lib/emailClipboard.js'; +import { downloadOutlookDraft } from '../../lib/outlookDraft.js'; import { useAuth } from '../../lib/AuthContext.jsx'; import Modal from '../Modal.jsx'; import ImageSlot from '../ImageSlot.jsx'; @@ -392,6 +393,16 @@ function EmailModal({ renc, onClose }) { } }; + const downloadOutlook = () => { + const slug = renc.titre.normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[^a-zA-Z0-9]+/g, '-').toLowerCase(); + downloadOutlookDraft({ + subject: data.subject, + html: data.html, + filename: `invitation-${slug}-outlook.eml`, + }); + flash('outlook'); + }; + const download = () => { const blob = new Blob([data.html], { type: 'text/html' }); const url = URL.createObjectURL(blob); @@ -429,8 +440,11 @@ function EmailModal({ renc, onClose }) { automatiquement. Videz un champ pour retirer ce bloc de l'email.

- +

- Collez l'email directement dans votre logiciel de messagerie (« Copier l'email » - conserve la mise en forme), ou envoyez le fichier .html avec votre outil d'emailing. + Pour Outlook, ouvrez le fichier .eml téléchargé : il charge directement le vrai corps HTML sans passer par le presse-papiers. La copie reste disponible pour les autres logiciels de messagerie.

diff --git a/web/src/lib/outlookDraft.js b/web/src/lib/outlookDraft.js new file mode 100644 index 0000000..12e8ee2 --- /dev/null +++ b/web/src/lib/outlookDraft.js @@ -0,0 +1,42 @@ +function utf8Base64(value) { + const bytes = new TextEncoder().encode(String(value ?? '')); + let binary = ''; + + for (let offset = 0; offset < bytes.length; offset += 0x8000) { + binary += String.fromCharCode(...bytes.subarray(offset, offset + 0x8000)); + } + + return globalThis.btoa(binary); +} + +function wrapBase64(value) { + return value.match(/.{1,76}/g)?.join('\r\n') ?? ''; +} + +export function buildOutlookDraftMime({ subject, html }) { + // X-Unsent asks Outlook to open the MIME message as a message to compose. + // Loading HTML as a real MIME body bypasses Outlook's destructive paste merge. + return [ + 'X-Unsent: 1', + `Subject: =?UTF-8?B?${utf8Base64(subject)}?=`, + 'MIME-Version: 1.0', + 'Content-Type: text/html; charset=UTF-8', + 'Content-Transfer-Encoding: base64', + '', + wrapBase64(utf8Base64(html)), + '', + ].join('\r\n'); +} + +export function downloadOutlookDraft({ subject, html, filename }) { + const mime = buildOutlookDraftMime({ subject, html }); + const blob = new Blob([mime], { type: 'message/rfc822' }); + const url = URL.createObjectURL(blob); + const anchor = document.createElement('a'); + anchor.href = url; + anchor.download = filename; + document.body.appendChild(anchor); + anchor.click(); + anchor.remove(); + setTimeout(() => URL.revokeObjectURL(url), 2000); +}