This is a submission for the Postmark Challenge: Inbox Innovators.
What I Built
I built Deejay, a system where people can request songs by simply sending an email with an youtube link. The email gets processed, the song is fetched from YouTube using the YoutubeAPI, and it appears in a real-time DJ console for approval. The UI allows the DJ to accept the request and play/queue it or reject it.
Demo
Code Repository
How I Built It
The Architecture Journey
Starting Simple: Email → Queue
The core concept was straightforward:
- Receive email with song request
- Parse the content (YouTube link or search query)
- Add to a queue
- Let the DJ manage it
Tech Stack Decisions
Backend: Express.js + TypeScript
// Clean, typed API endpoints
app.post('/api/queue/:id/approve', async (req, res) => {
const { id } = req.params;
const song = await queue.update(id, { status: 'approved' });
io.emit('queue-update', { queue: await queue.list() });
res.json({ success: true, song });
});
Real-time Updates: Socket.IO
// Instant updates to all connected clients
io.on('connection', (socket) => {
socket.emit('now-playing', playerState.getNowPlaying());
socket.emit('queue-update', { queue: await queue.list() });
});
Frontend: React + TypeScript + Tailwind
// Clean, responsive DJ console
function QueueItem({ song, onApprove, onReject }) {
return (
<div className="flex items-center gap-4 p-4 border rounded-lg">
<img src={song.thumbnail} className="w-16 h-16 rounded" />
<div className="flex-1">
<h3 className="font-semibold">{song.title}</h3>
<p className="text-sm text-gray-600">{song.artist}</p>
</div>
<div className="flex gap-2">
<Button onClick={() => onApprove(song.id)}>✅</Button>
<Button onClick={() => onReject(song.id)}>❌</Button>
</div>
</div>
);
}
The Email Processing Magic
The most interesting part was processing emails reliably. I used Postmark's inbound email service:
// Email webhook processor
router.post('/webhook', async (req, res) => {
const { content, requester } = extractEmailContent(req.body);
// Detect YouTube link or search query
const videoId = detectYouTubeLink(content);
let songData;
if (videoId) {
songData = await youtube.getVideoDetails(videoId);
} else {
songData = await youtube.search(content);
}
const song = {
id: uuidv4(),
title: songData.title,
requester,
status: 'pending',
submittedAt: new Date()
};
await queue.push(song);
io.emit('queue-update', { newSong: song });
});
Top comments (0)