Embed logo in Outlook drafts
This commit is contained in:
1 parent
40f314c540
commit
7bbf2e0d4d
3 files changed
+75
-20
No files matched your search
@@ -66,14 +66,19 @@ export function EmailCreatorTab() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadOutlook = () => {
|
const downloadOutlook = async () => {
|
||||||
const slug = form.subject.normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-|-$/g, '').toLowerCase() || 'email';
|
const slug = form.subject.normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-|-$/g, '').toLowerCase() || 'email';
|
||||||
downloadOutlookDraft({
|
try {
|
||||||
subject: form.subject,
|
setError('');
|
||||||
html: data.html,
|
await downloadOutlookDraft({
|
||||||
filename: `${slug}-outlook.eml`,
|
subject: form.subject,
|
||||||
});
|
html: data.html,
|
||||||
flash('outlook');
|
filename: `${slug}-outlook.eml`,
|
||||||
|
});
|
||||||
|
flash('outlook');
|
||||||
|
} catch (err) {
|
||||||
|
setError(err.message || "Impossible de créer le brouillon Outlook.");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const download = () => {
|
const download = () => {
|
||||||
|
|||||||
@@ -393,14 +393,19 @@ function EmailModal({ renc, onClose }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadOutlook = () => {
|
const downloadOutlook = async () => {
|
||||||
const slug = renc.titre.normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[^a-zA-Z0-9]+/g, '-').toLowerCase();
|
const slug = renc.titre.normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[^a-zA-Z0-9]+/g, '-').toLowerCase();
|
||||||
downloadOutlookDraft({
|
try {
|
||||||
subject: data.subject,
|
setError('');
|
||||||
html: data.html,
|
await downloadOutlookDraft({
|
||||||
filename: `invitation-${slug}-outlook.eml`,
|
subject: data.subject,
|
||||||
});
|
html: data.html,
|
||||||
flash('outlook');
|
filename: `invitation-${slug}-outlook.eml`,
|
||||||
|
});
|
||||||
|
flash('outlook');
|
||||||
|
} catch (err) {
|
||||||
|
setError(err.message || "Impossible de créer le brouillon Outlook.");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const download = () => {
|
const download = () => {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
function utf8Base64(value) {
|
const LOGO_CID = 'sbc-business-club-logo';
|
||||||
const bytes = new TextEncoder().encode(String(value ?? ''));
|
const MIME_BOUNDARY = '----=_SBC_Outlook_Draft_Logo';
|
||||||
|
|
||||||
|
function bytesBase64(bytes) {
|
||||||
let binary = '';
|
let binary = '';
|
||||||
|
|
||||||
for (let offset = 0; offset < bytes.length; offset += 0x8000) {
|
for (let offset = 0; offset < bytes.length; offset += 0x8000) {
|
||||||
@@ -9,27 +11,70 @@ function utf8Base64(value) {
|
|||||||
return globalThis.btoa(binary);
|
return globalThis.btoa(binary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function utf8Base64(value) {
|
||||||
|
return bytesBase64(new TextEncoder().encode(String(value ?? '')));
|
||||||
|
}
|
||||||
|
|
||||||
function wrapBase64(value) {
|
function wrapBase64(value) {
|
||||||
return value.match(/.{1,76}/g)?.join('\r\n') ?? '';
|
return value.match(/.{1,76}/g)?.join('\r\n') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildOutlookDraftMime({ subject, html }) {
|
function logoSource(html) {
|
||||||
|
return String(html).match(/\bsrc=["']([^"']*\/assets\/logo\.jpg(?:\?[^"']*)?)["']/i)?.[1] || '/assets/logo.jpg';
|
||||||
|
}
|
||||||
|
|
||||||
|
function useInlineLogo(html) {
|
||||||
|
return String(html).replace(
|
||||||
|
/(\bsrc\s*=\s*)(["'])(?:https?:\/\/[^"']+)?\/assets\/logo\.jpg(?:\?[^"']*)?\2/gi,
|
||||||
|
(_match, prefix, quote) => `${prefix}${quote}cid:${LOGO_CID}${quote}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildOutlookDraftMime({ subject, html, logoBase64 = '' }) {
|
||||||
// X-Unsent asks Outlook to open the MIME message as a message to compose.
|
// 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.
|
// Loading HTML as a real MIME body bypasses Outlook's destructive paste merge.
|
||||||
|
if (!logoBase64) {
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'X-Unsent: 1',
|
'X-Unsent: 1',
|
||||||
`Subject: =?UTF-8?B?${utf8Base64(subject)}?=`,
|
`Subject: =?UTF-8?B?${utf8Base64(subject)}?=`,
|
||||||
'MIME-Version: 1.0',
|
'MIME-Version: 1.0',
|
||||||
|
`Content-Type: multipart/related; type="text/html"; boundary="${MIME_BOUNDARY}"`,
|
||||||
|
'',
|
||||||
|
`--${MIME_BOUNDARY}`,
|
||||||
'Content-Type: text/html; charset=UTF-8',
|
'Content-Type: text/html; charset=UTF-8',
|
||||||
'Content-Transfer-Encoding: base64',
|
'Content-Transfer-Encoding: base64',
|
||||||
'',
|
'',
|
||||||
wrapBase64(utf8Base64(html)),
|
wrapBase64(utf8Base64(useInlineLogo(html))),
|
||||||
|
`--${MIME_BOUNDARY}`,
|
||||||
|
'Content-Type: image/jpeg; name="logo.jpg"',
|
||||||
|
'Content-Transfer-Encoding: base64',
|
||||||
|
`Content-ID: <${LOGO_CID}>`,
|
||||||
|
'Content-Disposition: inline; filename="logo.jpg"',
|
||||||
|
'',
|
||||||
|
wrapBase64(logoBase64),
|
||||||
|
`--${MIME_BOUNDARY}--`,
|
||||||
'',
|
'',
|
||||||
].join('\r\n');
|
].join('\r\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadOutlookDraft({ subject, html, filename }) {
|
export async function downloadOutlookDraft({ subject, html, filename }) {
|
||||||
const mime = buildOutlookDraftMime({ subject, html });
|
const response = await fetch(logoSource(html), { cache: 'force-cache' });
|
||||||
|
if (!response.ok) throw new Error("Le logo de l'e-mail n'a pas pu être chargé.");
|
||||||
|
|
||||||
|
const logoBase64 = bytesBase64(new Uint8Array(await response.arrayBuffer()));
|
||||||
|
const mime = buildOutlookDraftMime({ subject, html, logoBase64 });
|
||||||
const blob = new Blob([mime], { type: 'message/rfc822' });
|
const blob = new Blob([mime], { type: 'message/rfc822' });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const anchor = document.createElement('a');
|
const anchor = document.createElement('a');
|
||||||
|
|||||||
Reference in new issue
Block a user