Show HN: Mail Memories – A desktop app to rescue photos from Gmail
Hey HN, I’m the creator of Mail Memories. Like many of you, I've had my Gmail address for more than 20 years. A few years ago, I got curious and wanted to see what photos were buried deep in my account. I ended up finding lots of "lost" pictures of old friends, family members, and a ridiculous number of vintage memes. I originally built and launched this as a SaaS, but even with code and policies in place that kept users' photos private, I figured everyone would feel more comfortable with a desktop app. So, I threw out the server architecture and completely rewrote it as a 100% local desktop app for Mac and Windows. How it works now: The app connects directly to Google's server from your computer, processes everything entirely on your system, and saves photos straight to your hard drive. You can download your 50 oldest photos for free (no credit card required) just to see what's in there. If you want to download all the pictures in your account, it's a one-time payment of $29. No subscriptions. If you have an old, pre-2010 Gmail account, definitely give it a spin. You'll be surprised at what you find deep in your archive. I'd love to hear your feedback on the layout, scanning performance, or anything else. TL;DR: I turned my SaaS into a local desktop app (Mac/Windows) that recovers decades of forgotten photos from your Gmail. 100% local, no cloud, no subscriptions, no AI.
Discussion Highlights (15 comments)
tribal808
idk if other tools do it for free, but cool idea, hope that it gains the deserved visibility
baron3dl
First, I really love this idea, and I thank you for getting it into my head. That said, if no AI is really important, I guess it's worth $29, though I can't tell if you used AI to build it or not from here. Like, I just one-shot a script that does the same with Claude, after it listed 5 free projects that do the same, including one GUI. The whole thing took less time than writing this comment. Now, if it were $2.99, I probably would have just paid you.
KomoD
Or you can just use Google Takeout: https://takeout.google.com Deselect everything, select "Mail", create export, wait until it's done, and then download the zip.
Thaxll
For $30 you should sign your binary so you don't have a UAC popup. Also is it not doable with Google takeout ( with Gmail )?
murats
I like the idea. Google Takeout works, but a focused app that helps you actually find and recover old photos could still be useful.
shuirong
I like your idea. While installing the app, I suddenly had an idea for the logo: what do you think about using a tilted old photo of a child as the app icon?
artisinal
> 100% local, no cloud, no subscriptions, no AI. The world needs more of this
TazeTSchnitzel
If I have to look at yet another website with this same fucking AI-generated theme I'm gonna have to kill somebody.
ks2048
“I found photos of my niece I thought were lost forever. Thank you so much!” Emily D. Be honest, is "Emily D" a real person you got organic feedback from? Small thing that makes the vibed site off-putting. It says "Storage: 1.3 GB saved", but then says it is Read-only.
t_mahmood
Interesting! I already have a Python script that can download anything from Gmail. Making it a product?! Really have not thought about it! Which is why I am probably broke Ha Ha
nickjj
I'd love to somehow do the opposite of this but I don't think it's possible? It would be deleting attachments from emails without deleting the email thread. For example I'm always 1-2 GB away from my Google account being full. I've pruned Google Drive to the absolute bare minimum. I've had my Google account for a really long time. There's tens of thousands of emails since day 1. However, there's many emails that have attachments. For example my friends or someone might have sent me a bunch of images and there's a very long email thread going on with them. I want to delete the 300 MB of photos without deleting the email thread. I don't think Google has a way to do this. I'd easily be able to free up multiple gigs of space if this were possible. I've already bit the bullet and deleted the biggest offenders but I have a ton of emails with 1-2 attachments (pdfs, zip files, some images, etc.) that might "only" be 15 MB but I definitely don't want to delete the email since it has a record of something. Not just the attachment but the corresponding email chain.
benzofuran
Here's a gmail extractor google apps script that does the same thing, but for not $30! function autoExtractGmailMedia() { const START_TIME = Date.now(); const TIME_LIMIT = 1000 * 60 * 5; // 5 minutes (leaves a 1-minute safety buffer) const BATCH_SIZE = 50; const FOLDER_NAME = "Gmail_Media_Export"; // 1. Retrieve our current position from the script's property store const scriptProperties = PropertiesService.getScriptProperties(); let startIndex = parseInt(scriptProperties.getProperty('START_INDEX')) || 0; // Locate or create the destination folder let folder; const folders = DriveApp.getFoldersByName(FOLDER_NAME); if (folders.hasNext()) { folder = folders.next(); } else { folder = DriveApp.createFolder(FOLDER_NAME); } // 2. Process batches in a loop // Updated search query to ignore USPS and non-primary tabs const searchQuery = 'has:attachment -from:usps.gov -category:promotions -category:updates -category:social (filename:jpg OR filename:jpeg OR filename:png OR filename:zip)'; while (true) { const threads = GmailApp.search(searchQuery, startIndex, BATCH_SIZE); // If the search returns empty, we've hit the end of the inbox if (threads.length === 0) { console.log("Extraction completely finished."); scriptProperties.deleteProperty('START_INDEX'); deleteTriggers(); // Clean up so it doesn't keep running return; } for (let i = 0; i < threads.length; i++) { const messages = threads[i].getMessages(); for (let j = 0; j < messages.length; j++) { const attachments = messages[j].getAttachments(); for (let k = 0; k < attachments.length; k++) { const attachment = attachments[k]; const name = attachment.getName().toLowerCase(); const type = attachment.getContentType(); const size = attachment.getSize(); // Apply size threshold (102,400 bytes = 100KB) and file type filter if (size > 102400) { if (type.includes('image/') || name.endsWith('.zip')) { folder.createFile(attachment); } } } } } // Increment our starting index for the next batch startIndex += BATCH_SIZE; // 3. The Stopwatch Check if (Date.now() - START_TIME > TIME_LIMIT) { console.log(`Approaching timeout at index ${startIndex}. Saving state and passing the baton...`); scriptProperties.setProperty('START_INDEX', startIndex.toString()); scheduleNextRun(); return; // Exit to avoid the hard timeout exception } } } function scheduleNextRun() { deleteTriggers(); // Prevent duplicate overlapping triggers ScriptApp.newTrigger("autoExtractGmailMedia") .timeBased() .after(60 * 1000) // Fire a new execution 1 minute from now .create(); } function deleteTriggers() { const triggers = ScriptApp.getProjectTriggers(); for (let i = 0; i < triggers.length; i++) { if (triggers[i].getHandlerFunction() === "autoExtractGmailMedia") { ScriptApp.deleteTrigger(triggers[i]); } } }
ksajadi
Meta: Can someone more familiar with the rules of HN please tell me why some Show HN posts get immediately “flagged” while others don’t? I have seen commercial entires like this be flagged while this one is on the first page.
ltiger
Just wanted to take a moment to say thank you to everyone who commented today. Launching on HN isn't for the faint of heart, but it’s been really valuable. What a day. I was told my landing page looks like an AI wrote it, got roasted for a confusing illustration metric (and rightly so), and received the ultimate rite of passage: being told my app could be replaced by a couple of Linux CLI commands. Unironically, thanks everyone. Because of your feedback, the site copy's a little tighter, and the Windows installer no longer throws a scary UAC prompt. I couldn't have asked for a better (or more intense) test.
adamtheturtle
Whether or not I could have got this stuff out without the app, I wasn't going to, and I already have $29 worth of nostalgia out of it. Thank you