blog and backlinks

This commit is contained in:
Timo Knuth
2026-04-14 10:35:29 +02:00
parent f5fd33a304
commit ff3294291f
30 changed files with 3153 additions and 7 deletions

View File

@@ -0,0 +1,384 @@
import nodemailer from 'nodemailer';
import dotenv from 'dotenv';
import path from 'path';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
dotenv.config({ path: path.resolve(process.cwd(), '.env') });
dayjs.extend(utc);
dayjs.extend(timezone);
const SMTP_HOST = process.env.SMTP_HOST;
const SMTP_PORT = parseInt(process.env.SMTP_PORT || '465');
const SMTP_USER = process.env.SMTP_USER;
const SMTP_PASS = process.env.SMTP_PASS;
const TEST_EMAIL = 'timo@qrmaster.net';
interface OutreachEmail {
id: number;
tier: number;
name: string;
recipient: string;
subject: string;
body: string;
language: 'DE' | 'EN';
}
const EMAILS: OutreachEmail[] = [
{
id: 1,
tier: 3,
name: 'eEducation Austria',
recipient: 'eeducation@bildung.gv.at',
language: 'DE',
subject: 'eTapas-Liste Tool-Ergänzung',
body: `Hallo,
in eurer eTapas-Liste fehlt bislang ein QR-Code-Generator. Lehrkräfte nutzen QR-Codes häufig, um Arbeitsblätter oder Hörbeispiele direkt zugänglich zu machen Schüler scannen, fertig, kein Link-Tippen.
qrmaster.net ist werbefrei und für einfache Codes ohne Anmeldung nutzbar. Falls ein Ziel-Link später noch geändert werden muss, ohne neu zu drucken, bieten wir auch dynamische QR-Codes an (erfordert einen kostenlosen Account).
Entspricht das euren Kriterien für eine Aufnahme in die Liste?
Viele Grüße,
Timo | Founder, qrmaster.net`
},
{
id: 2,
tier: 1,
name: 'Promethean World',
recipient: 'info@prometheanworld.com',
language: 'DE',
subject: 'Ergänzung zu eurem Artikel über digitale Tools',
body: `Hallo,
in eurem Beitrag zu digitalen Tools im Lehreralltag geht es viel ums Teilen von Inhalten Whiteboards, Classroom-Workflows, digitale Materialien. Was oft fehlt: ein Weg, Links sekundenschnell auf Papier zugänglich zu machen.
QR-Codes lösen genau das. qrmaster.net erstellt sie kostenlos und für statische Codes ohne Anmeldung. Unsere dynamischen QR-Codes erlauben es sogar, den Ziel-Link später noch zu ändern, falls sich Materialien aktualisieren (erfordert einen einfachen Account-Login).
Wäre das eine sinnvolle Ergänzung für den Artikel?
Viele Grüße,
Timo | Founder, qrmaster.net`
},
{
id: 3,
tier: 2,
name: 'The Startup Project',
recipient: 'hello@startupproject.org',
language: 'EN',
subject: 'missing tool in your startup resources',
body: `Hi,
Your startup resource list covers all the bases product, funding, marketing. One gap I noticed: no QR code generator.
Founders use them more than they expect product packaging, pitch decks, business cards. qrmaster.net is free and works without an account for static codes. For more flexibility, we also offer dynamic QR codes so you can update the destination later without reprinting (requires a free account).
Worth adding to the marketing tools section?
Best,
Timo | Founder, qrmaster.net`
},
{
id: 4,
tier: 1,
name: 'Cadmium',
recipient: 'jessie.reyes@gocadmium.com',
language: 'EN',
subject: 'one tool missing from your event management list',
body: `Hi Jessie,
Your "10 best event management tools" covers the core stack well. One gap: no QR code generator.
Event planners use them for check-in flows, session schedules, and feedback forms. qrmaster.net handles bulk generation and includes scan analytics. While basic codes are account-free, our dynamic QR codes let planners update destinations post-printing (requires a free account).
Would it make sense to add alongside your existing recommendations?
Best,
Timo | Founder, qrmaster.net`
},
{
id: 5,
tier: 2,
name: 'EssayGrader',
recipient: 'support@essaygrader.ai',
language: 'EN',
subject: 'one gap in your 76-resource list',
body: `Hi,
Your teacher resource list covers a lot of ground. One thing missing: a QR code generator.
Teachers use them to link printed handouts to digital content without students typing URLs. qrmaster.net is free and doesn't require an account for static codes. We also offer dynamic QR codes for those who need to update links later (requires a simple account setup).
Would it fit your inclusion criteria?
Best,
Timo | Founder, qrmaster.net`
},
{
id: 6,
tier: 3,
name: 'Serkan Cagatay',
recipient: 'info@serkancagatay.com',
language: 'DE',
subject: 'Tool-Tipp für deine Ressourcen-Liste',
body: `Hallo Serkan,
auf deiner Seite mit didaktischen Ressourcen fehlt ein Weg, Audiodateien oder Notenlinks direkt im Unterricht zugänglich zu machen.
qrmaster.net macht genau das: QR-Code in Sekunden, ohne Account für einfache Codes. Falls du dynamische Codes brauchst, die man nachträglich umleiten kann, bieten wir das mit einem kostenlosen Account ebenfalls an.
Passt das in deine Sammlung?
Viele Grüße,
Timo | Founder, qrmaster.net`
},
{
id: 7,
tier: 1,
name: 'U.S. Chamber',
recipient: 'jmulvey@uschamber.com',
language: 'EN',
subject: 'free tool gap in your small business resources',
body: `Hi Jeanette,
Your list of free resources for small businesses is excellent. One tool I'd expect to see: a reliable QR code generator.
Small business owners use them for menus, signage, and packaging. qrmaster.net is 100% free and account-free for static codes. Our dynamic QR codes allow owners to update destinations without reprinting, which helps avoid wasted materials (requires a free account).
Would it make sense to include it in the marketing tools section?
Best,
Timo | Founder, qrmaster.net`
},
{
id: 8,
tier: 1,
name: 'Teaching Channel',
recipient: 'support@teachingchannel.com',
language: 'EN',
subject: 'missing tool from your digital resources list',
body: `Hi,
Your roundup of 10 digital resources covers a solid range. One tool that's consistently useful for bridging physical and digital: a QR code generator.
qrmaster.net works without an account for simple codes. We also provide dynamic QR codes for teachers who want to update the link destination later without reprinting materials (requires a free account).
Would it be a fit for your list?
Best,
Timo | Founder, qrmaster.net`
},
{
id: 9,
tier: 2,
name: 'Teachers of Tomorrow',
recipient: 'MediaRelations@TeachersofTomorrow.org',
language: 'EN',
subject: 'resource suggestion for new teachers',
body: `Hi,
Your guide on teaching resources is a solid reference. One practical gap: no QR code generator.
QR codes help teachers set up learning stations and share links without a projector. qrmaster.net is free and account-free for static codes. For dynamic management—allowing links to be updated post-printing—we offer a dedicated dashboard (requires a free account).
Does it fit what you'd add to the guide?
Best,
Timo | Founder, qrmaster.net`
},
{
id: 10,
tier: 2,
name: 'Montgomery College',
recipient: 'CTL@montgomerycollege.edu',
language: 'EN',
subject: 'tool suggestion for your tech tools page',
body: `Hi CTL Team,
Your "Tech Tools to Support Teaching and Learning" page is a useful reference. One tool missing: a straightforward QR code generator.
qrmaster.net is free and doesn't require an account for basic codes. We also support dynamic QR codes, which allow faculty to update link destinations mid-semester without reprinting handouts (requires a free account).
Would it be worth adding to your list?
Best,
Timo | Founder, qrmaster.net`
},
{
id: 11,
tier: 3,
name: 'PHSG',
recipient: 'info@phsg.ch',
language: 'DE',
subject: 'Ergänzung zu euren ICT-Ressourcen',
body: `Hallo,
eure ICT-Ressourcen-Seite deckt Medien und Programmierung gut ab. Was noch fehlt: ein einfaches Werkzeug, um Links zu solchen Projekten direkt im Unterricht per QR-Code zu teilen.
qrmaster.net ist für einfache Codes ohne Anmeldung nutzbar. Mit unseren dynamischen QR-Codes lässt sich der Ziel-Link auch nachträglich noch ändern, falls sich ein Projekt verschiebt (erfordert einen kostenlosen Account).
Wäre das eine Ergänzung für eure Liste?
Herzliche Grüße,
Timo | Founder, qrmaster.net`
},
{
id: 12,
tier: 2,
name: 'Super Monitoring',
recipient: 'stuart@surges.co',
language: 'EN',
subject: 'tool your audience probably uses weekly',
body: `Hi Stuart,
Your post on marketing tools is a great read. One category often overlooked: QR code generators.
Marketers use them for direct mail, packaging, and OOH. qrmaster.net provides bulk generation and scan analytics. Static codes are account-free, while our dynamic QR codes allow for post-printing updates (requires a free account).
Would it fit as a mention in the article?
Cheers,
Timo | Founder, qrmaster.net`
},
{
id: 13,
tier: 3,
name: 'Kunstunterricht',
recipient: 'simon@kunstunterricht-ideen.de',
language: 'DE',
subject: 'Tool-Tipp für deine Online-Ressourcen',
body: `Hallo Simon,
auf deiner Ressourcen-Seite für Kunstunterricht fehlt ein praktisches Werkzeug: ein QR-Code-Generator. Damit können Lehrkräfte Links zu Tutorials oder digitalen Museen direkt auf Ausdrucke packen.
qrmaster.net ist für statische Codes ohne Anmeldung nutzbar. Dynamische QR-Codes erlauben nachträgliche Änderungen am Ziel-Link, falls sich die Quelle ändert (erfordert einen kostenlosen Account).
Wäre das etwas für deine Liste?
Kreative Grüße,
Timo | Founder, qrmaster.net`
},
{
id: 14,
tier: 1,
name: 'TeachThought',
recipient: 'terry@teachthought.com',
language: 'EN',
subject: 'gap in your 21 literacy resources',
body: `Hi Terry,
Your 21 literacy resources list covers annotation and digital storytelling—but no easy way to bridge physical books with digital resources.
qrmaster.net is free and doesn't require an account for basic codes. We also offer dynamic QR codes, allowing teachers to update destinations post-printing as literacy plans evolve (requires a free account).
Would it fit alongside your existing literacy tools?
Best,
Timo | Founder, qrmaster.net`
},
{
id: 15,
tier: 1,
name: 'Tripleseat',
recipient: 'info@tripleseat.com',
language: 'EN',
subject: 'tool suggestion for your event planning resources',
body: `Hi,
Your event planning resources page is a solid reference. One practical tool missing: a clean QR code generator.
Venue planners use them for digital menus and schedules. qrmaster.net supports bulk generation and scan analytics. While static codes are account-free, we also offer dynamic QR codes for updating destinations after printing (requires a free account).
Would it fit your resource page?
Best,
Timo | Founder, qrmaster.net`
}
];
async function sendEmail(email: OutreachEmail, isTest: boolean) {
const transporter = nodemailer.createTransport({
host: SMTP_HOST,
port: SMTP_PORT,
secure: SMTP_PORT === 465,
auth: {
user: SMTP_USER,
pass: SMTP_PASS,
},
});
const mailOptions = {
from: `"Timo | qrmaster.net" <${SMTP_USER}>`,
to: isTest ? TEST_EMAIL : email.recipient,
subject: isTest ? `[TEST] ${email.subject}` : email.subject,
text: email.body,
};
try {
const info = await transporter.sendMail(mailOptions);
console.log(`[${email.id}] Email sent to ${mailOptions.to}: ${info.messageId}`);
} catch (error) {
console.error(`[${email.id}] Error sending email to ${mailOptions.to}:`, error);
}
}
async function run() {
const args = process.argv.slice(2);
const isTest = args.includes('--test');
const isSchedule = args.includes('--schedule');
const isDryRun = args.includes('--dry-run');
if (!isTest && !isSchedule && !isDryRun) {
console.log('Usage: tsx outreach-resource-emails.ts [--test | --schedule | --dry-run]');
return;
}
if (isDryRun) {
console.log('--- DRY RUN: Showing refined 15 emails ---');
EMAILS.forEach(email => {
console.log(`\n--- Target: ${email.name} (#${email.id}) ---`);
console.log(`Subject: ${email.subject}`);
console.log(`Body:\n${email.body}\n`);
});
return;
}
if (isTest) {
console.log(`--- Sending 15 refined test emails to ${TEST_EMAIL} ---`);
for (const email of EMAILS) {
await sendEmail(email, true);
}
console.log('--- Test send completed ---');
}
if (isSchedule) {
const targetTime = dayjs().tz('Europe/Berlin').add(1, 'day').hour(15).minute(30).second(0).millisecond(0);
const now = dayjs().tz('Europe/Berlin');
console.log(`Current Time (CEST): ${now.format('YYYY-MM-DD HH:mm:ss')}`);
console.log(`Target Time (CEST): ${targetTime.format('YYYY-MM-DD HH:mm:ss')}`);
const waitMs = targetTime.diff(now);
if (waitMs <= 0) {
console.error('Target time is in the past!');
return;
}
console.log(`Waiting ${Math.round(waitMs / 1000 / 60 / 60 * 10) / 10} hours...`);
setTimeout(async () => {
console.log('--- Starting scheduled outreach ---');
for (const email of EMAILS) {
await sendEmail(email, false);
}
console.log('--- Scheduled outreach completed ---');
}, waitMs);
}
}
run();