1
0
Fork 0

wip: Work on i18n support for newsletter

This commit is contained in:
Joost De Cock 2024-01-01 15:55:49 +01:00
parent 3cd8ecd392
commit aff8714daa
5 changed files with 126 additions and 81 deletions

View file

@ -15,3 +15,4 @@ all:
backend3.freesewing.org: backend3.freesewing.org:
monorepo: /fs/monorepo monorepo: /fs/monorepo

View file

@ -1,10 +1,14 @@
export const testers = [ export const testers = {
{ en: [
email: 'joost@joost.at', {
ehash: 'asefsdfsdfsdlfsllehash', email: 'joost@joost.at',
}, ehash: 'asefsdfsdfsdlfsllehash',
{ },
email: 'joost@decock.org', ],
ehash: 'zlasdadfsdlfsjjuehash', nl: [
}, {
] email: 'joost@decock.org',
ehash: 'zlasdadfsdlfsjjuehash',
},
],
}

View file

@ -19,7 +19,7 @@
<!-- Tell iOS not to automatically link certain text strings. --> <!-- Tell iOS not to automatically link certain text strings. -->
<meta name="color-scheme" content="light" /> <meta name="color-scheme" content="light" />
<meta name="supported-color-schemes" content="light" /> <meta name="supported-color-schemes" content="light" />
<title>FreeSewing Newsletter</title> <title>{{ title }}</title>
<!-- The title tag shows in email notifications, like Android 4.4. --> <!-- The title tag shows in email notifications, like Android 4.4. -->
<!-- What it does: Makes background images in 72ppi Outlook render at correct size. --> <!-- What it does: Makes background images in 72ppi Outlook render at correct size. -->
@ -323,7 +323,7 @@
" "
> >
<a href="https://freesewing.org/patrons/join" <a href="https://freesewing.org/patrons/join"
><b>Support FreeSewing: Become a Patron</b></a ><b>{{ support }}</b></a
> >
</td> </td>
</tr> </tr>
@ -356,8 +356,7 @@
> >
<br /><br /> <br /><br />
<unsubscribe style="color: #ffffff; text-decoration: underline"> <unsubscribe style="color: #ffffff; text-decoration: underline">
You can <a href="{{{ unsubscribe }}}">unsubscribe</a> at any time. Or just reply and <a href="{{{ unsubscribe }}}">{{ unsub1 }}</a>. {{ unsub2 }}
tell us you want out.
</unsubscribe> </unsubscribe>
</td> </td>
</tr> </tr>

View file

@ -103,6 +103,7 @@
"c8": "^8.0.0", "c8": "^8.0.0",
"eslint-config-next": "^14.0.1", "eslint-config-next": "^14.0.1",
"glob": "^10.3.10", "glob": "^10.3.10",
"rehype-format": "^5.0.0",
"yarn": "^1.22.19" "yarn": "^1.22.19"
}, },
"packageManager": "yarn@1.22.19" "packageManager": "yarn@1.22.19"

View file

@ -12,10 +12,50 @@ import { testers } from '../config/newsletter-testers.mjs'
import { fileURLToPath } from 'url' import { fileURLToPath } from 'url'
import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2' import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2'
console.log({ edition: process.env.NL_EDITION })
// Current working directory // Current working directory
const cwd = path.dirname(fileURLToPath(import.meta.url)) const cwd = path.dirname(fileURLToPath(import.meta.url))
const backend = 'https://backend.freesewing.org/' const backend = 'https://backend3.freesewing.org/'
const i18n = {
en: {
title: 'FreeSewing newsletter',
support: 'Support FreeSewing: Become a patron',
unsub1: 'You can unsubscribe at any time',
unsub2: 'Or reply and tell us you want out',
},
nl: {
title: 'FreeSewing nieuwsbrief',
support: 'Steun FreeSewing: Wordt mecenas',
unsub1: 'Je kan je op elk moment uitschrijven',
unsub2: 'Of stuur een reply en laat ons weten dat het niet meer hoeft',
},
fr: {
title: "Bulletin d'info FreeSewing",
support: 'Soutenir FreeSewing : Devenir mécène',
unsub1: 'Vous pouvez vous désabonner à tout moment',
unsub2: 'Ou répondez et dites-nous que vous voulez vous désabonner',
},
de: {
title: 'FreeSewing-Newsletter',
support: 'Unterstützen Sie FreeSewing: Werden Sie Gönner',
unsub1: 'Sie können sich jederzeit wieder abmelden',
unsub2: 'Oder antworten Sie uns und sagen Sie uns, dass Sie nicht mehr wollen',
},
de: {
title: 'FBoletín FreeSewing',
support: 'Apoya FreeSewing: Hazte mecenas',
unsub1: 'Puedes darte de baja en cualquier momento',
unsub2: 'O contesta y dinos que quieres darte de baja',
},
de: {
title: 'Інформаційний бюлетень FreeSewing',
support: 'Підтримайте FreeSewing: Стати меценатом',
unsub1: 'Ви можете відписатися в будь-який час',
unsub2: 'Або надішліть нам відповідь і скажіть, що хочете відмовитися',
},
}
const asHtml = async (text) => { const asHtml = async (text) => {
const content = await unified() const content = await unified()
@ -29,20 +69,13 @@ const asHtml = async (text) => {
return content.value return content.value
} }
const getToken = async () => {
let res = await axios.post(`${backend}login`, {
username: process.env.FS_USER,
password: process.env.FS_PASSWORD,
})
if (res.data) return res.data.token
else if (res.err) return console.log(res.err)
}
const getSubscribers = async (test = true) => { const getSubscribers = async (test = true) => {
if (test) return testers if (test) return testers
let token = await getToken()
let res = await axios.get(`${backend}admin/subscribers`, { let res = await axios.get(`${backend}admin/subscribers`, {
headers: { Authorization: 'Bearer ' + token }, auth: {
username: process.env.NL_API_KEY,
password: process.env.NL_API_SECRET,
},
}) })
if (res.data) return res.data if (res.data) return res.data
else return false else return false
@ -51,75 +84,82 @@ const getSubscribers = async (test = true) => {
const send = async (test = true) => { const send = async (test = true) => {
const us = 'FreeSewing <info@freesewing.org>' const us = 'FreeSewing <info@freesewing.org>'
const template = fs.readFileSync(`${cwd}/../config/templates/newsletter.html`, 'utf8') const template = fs.readFileSync(`${cwd}/../config/templates/newsletter.html`, 'utf8')
let edition
try {
edition = await axios.get(
`https://posts.freesewing.org/newsletters?slug_eq=${process.env.NL_EDITION}`,
'utf8'
)
} catch (err) {
console.log(err)
process.exit()
}
const text = edition.data[0].body
const subscribers = await getSubscribers(test) const subscribers = await getSubscribers(test)
const content = await asHtml(text)
const inject = { content }
// Oh AWS your APIs are such a clusterfuck // Oh AWS your APIs are such a clusterfuck
const client = new SESv2Client({ region: 'us-east-1' }) const client = new SESv2Client({ region: 'us-east-1' })
let i = 1 let i = 1
subscribers.sort() let l = 1
let subs = subscribers.length for (const lang in subscribers) {
for (let sub of subscribers) { let edition
// If your SMTP relay start rate-limiting midway through try {
// you can use this if loop to start just after the last edition = await axios.get(
// successful delivery `https://raw.githubusercontent.com/freesewing/freesewing/develop/markdown/org/newsletter/${process.env.NL_EDITION}/${lang}.md`,
if (i > 0) { 'utf8'
let unsub = `${backend}newsletter/unsubscribe/${sub.ehash}` )
inject.unsubscribe = unsub } catch (err) {
let body = mustache.render(template, inject) console.log(err)
console.log(`${i}/${subs} Sending to ${sub.email}`) process.exit()
}
console.log(edition.data)
const text = edition.data[0].body
const content = await asHtml(text)
// Via API console.log(content)
const command = new SendEmailCommand({
ConfigurationSetName: 'Newsletter', process.exit()
Content: {
Simple: { subscribers[lang].sort()
Body: { let subs = subscribers[lang].length
Text: { for (let sub of subscribers[lang]) {
Charset: 'utf-8', if (i > 0) {
Data: text, let unsub = `${backend}newsletter/unsubscribe/${sub.ehash}`
inject.unsubscribe = unsub
let body = mustache.render(template, {
...i18n[lang],
content,
})
console.log(`[${lang}] ${i}/${subs} Sending to ${sub.email}`)
// Via API
const command = new SendEmailCommand({
ConfigurationSetName: 'Newsletter',
Content: {
Simple: {
Body: {
Text: {
Charset: 'utf-8',
Data: text,
},
Html: {
Charset: 'utf-8',
Data: body,
},
}, },
Html: { Subject: {
Charset: 'utf-8', Charset: 'utf-8',
Data: body, Data: 'FreeSewing newsletter: Autumn 2023',
}, },
}, },
Subject: {
Charset: 'utf-8',
Data: 'FreeSewing newsletter: Autumn 2023',
},
}, },
}, Destination: {
Destination: { ToAddresses: [sub.email],
ToAddresses: [sub.email], },
}, //FeedbackForwardingEmailAddress: us,
//FeedbackForwardingEmailAddress: us, FromEmailAddress: us,
FromEmailAddress: us, //FromEmailAddressIdentityArn: "arn:aws:ses:us-east-1:550348293871:identity/freesewing.org",
//FromEmailAddressIdentityArn: "arn:aws:ses:us-east-1:550348293871:identity/freesewing.org", //ReplyToAddresses: us,
//ReplyToAddresses: us, })
}) //try {
try { // await client.send(command)
await client.send(command) //} catch (err) {
} catch (err) { // console.log(err)
console.log(err) // return false
return false //}
} }
i++
} }
i++
} }
} }