package main import ( "encoding/json" "fmt" "log" "os" "sort" "strings" ) type CleanupRecommendations struct { SafeToDelete []DeleteRecommendation `json:"safe_to_delete"` BulkArchive []ArchiveRecommendation `json:"bulk_archive"` UnsubscribeTargets []UnsubscribeTarget `json:"unsubscribe_targets"` AttentionNeeded []AttentionItem `json:"attention_needed"` StorageStats StorageStats `json:"storage_stats"` } type DeleteRecommendation struct { Category string `json:"category"` Query string `json:"query"` Count int `json:"estimated_count"` Description string `json:"description"` Risk string `json:"risk"` Examples []string `json:"examples"` } type ArchiveRecommendation struct { Category string `json:"category"` Query string `json:"query"` Count int `json:"estimated_count"` Description string `json:"description"` Reason string `json:"reason"` } type UnsubscribeTarget struct { Sender string `json:"sender"` Count int `json:"count"` LastEmail string `json:"last_email"` Category string `json:"category"` Priority string `json:"priority"` Reason string `json:"reason"` } type AttentionItem struct { Category string `json:"category"` Query string `json:"query"` Count int `json:"count"` Description string `json:"description"` Action string `json:"recommended_action"` } type StorageStats struct { TotalEmails int `json:"total_emails"` DeletionPotential int `json:"deletion_potential"` ArchivePotential int `json:"archive_potential"` PercentageReduction float64 `json:"percentage_reduction"` CategoryBreakdown map[string]int `json:"category_breakdown"` } func main() { if len(os.Args) < 2 { fmt.Println("Usage: go run cleanup.go [output_format]") fmt.Println(" analysis_json_file: JSON output from analyze.go") fmt.Println(" output_format: summary (default), detailed, or json") os.Exit(1) } jsonFile := os.Args[1] outputFormat := "summary" if len(os.Args) > 2 { outputFormat = strings.ToLower(os.Args[2]) } stats, err := loadAnalysisFromJSON(jsonFile) if err != nil { log.Fatalf("Error loading analysis JSON: %v", err) } recommendations := generateCleanupRecommendations(stats) switch outputFormat { case "summary": printSummary(recommendations) case "detailed": printDetailed(recommendations) case "json": outputJSON(recommendations) default: fmt.Printf("Unknown output format: %s\n", outputFormat) os.Exit(1) } } func loadAnalysisFromJSON(filename string) (EmailStats, error) { var stats EmailStats file, err := os.Open(filename) if err != nil { return stats, err } defer file.Close() decoder := json.NewDecoder(file) err = decoder.Decode(&stats) return stats, err } func generateCleanupRecommendations(stats EmailStats) CleanupRecommendations { recommendations := CleanupRecommendations{ SafeToDelete: []DeleteRecommendation{}, BulkArchive: []ArchiveRecommendation{}, UnsubscribeTargets: []UnsubscribeTarget{}, AttentionNeeded: []AttentionItem{}, StorageStats: StorageStats{ TotalEmails: stats.TotalEmails, CategoryBreakdown: stats.Categories, }, } // Generate safe delete recommendations recommendations.SafeToDelete = generateDeleteRecommendations(stats) // Generate bulk archive recommendations recommendations.BulkArchive = generateArchiveRecommendations(stats) // Generate unsubscribe targets recommendations.UnsubscribeTargets = generateUnsubscribeTargets(stats) // Generate attention needed items recommendations.AttentionNeeded = generateAttentionItems(stats) // Calculate storage impact recommendations.StorageStats = calculateStorageImpact(stats, recommendations) return recommendations } func generateDeleteRecommendations(stats EmailStats) []DeleteRecommendation { var recommendations []DeleteRecommendation // Old promotional emails if count, ok := stats.Categories["newsletters"]; ok && count > 50 { recommendations = append(recommendations, DeleteRecommendation{ Category: "Old Newsletters", Query: `subject:(newsletter OR weekly OR monthly) older_than:6m`, Count: count / 2, // Estimate half are old Description: "Newsletter emails older than 6 months", Risk: "Low", Examples: []string{"Weekly digest emails", "Monthly newsletters", "Company updates"}, }) } // Old social media notifications if socialCount := countSocialEmails(stats.TopDomains); socialCount > 30 { recommendations = append(recommendations, DeleteRecommendation{ Category: "Social Media Notifications", Query: `from:(facebook OR twitter OR linkedin OR instagram) older_than:2m`, Count: socialCount * 2 / 3, // Estimate 2/3 are old Description: "Social media notifications older than 2 months", Risk: "Low", Examples: []string{"Facebook notifications", "Twitter alerts", "LinkedIn updates"}, }) } // Old promotional emails promotionalCount := 0 for _, pattern := range stats.SubjectPatterns { if pattern.Pattern == "promotional" { promotionalCount = pattern.Count break } } if promotionalCount > 20 { recommendations = append(recommendations, DeleteRecommendation{ Category: "Old Promotions", Query: `subject:(sale OR deal OR offer OR discount) older_than:3m`, Count: promotionalCount * 3 / 4, // Estimate 3/4 are old Description: "Promotional/sales emails older than 3 months", Risk: "Low", Examples: []string{"Sales announcements", "Discount offers", "Flash sales"}, }) } // Automated system emails automatedCount := countAutomatedEmails(stats.TopDomains) if automatedCount > 40 { recommendations = append(recommendations, DeleteRecommendation{ Category: "Old System Notifications", Query: `from:(noreply OR no-reply) subject:(notification OR alert) older_than:1y`, Count: automatedCount / 2, Description: "System notifications and alerts older than 1 year", Risk: "Medium", Examples: []string{"System alerts", "Automated notifications", "Service updates"}, }) } return recommendations } func generateArchiveRecommendations(stats EmailStats) []ArchiveRecommendation { var recommendations []ArchiveRecommendation // Archive newsletters if count, ok := stats.Categories["newsletters"]; ok && count > 30 { recommendations = append(recommendations, ArchiveRecommendation{ Category: "All Newsletters", Query: `from:(noreply OR no-reply) OR subject:(newsletter OR unsubscribe)`, Count: count, Description: "Move all newsletter-type emails out of inbox", Reason: "Newsletters rarely require immediate action", }) } // Archive social media if count, ok := stats.Categories["social"]; ok && count > 20 { recommendations = append(recommendations, ArchiveRecommendation{ Category: "Social Media", Query: `from:(facebook OR twitter OR linkedin OR instagram OR youtube)`, Count: count, Description: "Move social media notifications out of inbox", Reason: "Social notifications can be checked on the platforms directly", }) } // Archive automated emails automatedCount := countAutomatedEmails(stats.TopDomains) if automatedCount > 25 { recommendations = append(recommendations, ArchiveRecommendation{ Category: "Automated Emails", Query: `from:(noreply OR no-reply OR automated)`, Count: automatedCount, Description: "Move automated system emails out of inbox", Reason: "Automated emails are usually informational only", }) } return recommendations } func generateUnsubscribeTargets(stats EmailStats) []UnsubscribeTarget { var targets []UnsubscribeTarget // High-volume newsletter senders for _, sender := range stats.TopSenders { if sender.Count <= 10 { break } priority := "medium" reason := "" category := "" email := strings.ToLower(sender.Email) if strings.Contains(email, "noreply") || strings.Contains(email, "no-reply") { category = "automated" if sender.Count > 50 { priority = "high" reason = "Very high volume automated sender" } else if sender.Count > 25 { priority = "medium" reason = "High volume automated sender" } else { priority = "low" reason = "Moderate volume automated sender" } } else if strings.Contains(email, "newsletter") || strings.Contains(email, "marketing") { category = "newsletter" priority = "medium" reason = "Newsletter or marketing emails" } else if containsSocialDomain(sender.Domain) { category = "social" priority = "low" reason = "Social media notifications" } else { category = "other" priority = "low" reason = "High volume sender - review manually" } if sender.Count > 15 { targets = append(targets, UnsubscribeTarget{ Sender: sender.Email, Count: sender.Count, Category: category, Priority: priority, Reason: reason, }) } } // Sort by priority and count sort.Slice(targets, func(i, j int) bool { if targets[i].Priority != targets[j].Priority { priorityOrder := map[string]int{"high": 3, "medium": 2, "low": 1} return priorityOrder[targets[i].Priority] > priorityOrder[targets[j].Priority] } return targets[i].Count > targets[j].Count }) return targets } func generateAttentionItems(stats EmailStats) []AttentionItem { var items []AttentionItem // High volume personal senders for _, sender := range stats.TopSenders { if sender.Count > 50 && !strings.Contains(strings.ToLower(sender.Email), "noreply") && !containsAutomatedKeywords(sender.Email) { items = append(items, AttentionItem{ Category: "High Volume Personal", Query: fmt.Sprintf(`from:%s`, sender.Email), Count: sender.Count, Description: fmt.Sprintf("Very high email volume from %s", sender.Email), Action: "Review relationship or create filters", }) } } // Old unread emails items = append(items, AttentionItem{ Category: "Old Unread", Query: `is:unread older_than:1m`, Count: 0, // Would need additional analysis Description: "Unread emails older than 1 month", Action: "Review and either read, archive, or delete", }) // Large attachments items = append(items, AttentionItem{ Category: "Large Attachments", Query: `has:attachment larger:10M`, Count: 0, // Would need additional analysis Description: "Emails with attachments larger than 10MB", Action: "Review and download important files, then delete emails", }) return items } func calculateStorageImpact(stats EmailStats, recommendations CleanupRecommendations) StorageStats { deletionPotential := 0 archivePotential := 0 for _, rec := range recommendations.SafeToDelete { deletionPotential += rec.Count } for _, rec := range recommendations.BulkArchive { archivePotential += rec.Count } totalReduction := deletionPotential + archivePotential percentageReduction := float64(totalReduction) / float64(stats.TotalEmails) * 100 return StorageStats{ TotalEmails: stats.TotalEmails, DeletionPotential: deletionPotential, ArchivePotential: archivePotential, PercentageReduction: percentageReduction, CategoryBreakdown: stats.Categories, } } func countSocialEmails(domains []DomainInfo) int { count := 0 for _, domain := range domains { if domain.Type == "social" { count += domain.Count } } return count } func countAutomatedEmails(domains []DomainInfo) int { count := 0 for _, domain := range domains { if domain.Type == "automated" { count += domain.Count } } return count } func containsSocialDomain(domain string) bool { socialDomains := []string{"facebook", "twitter", "linkedin", "instagram", "youtube", "tiktok"} domain = strings.ToLower(domain) for _, social := range socialDomains { if strings.Contains(domain, social) { return true } } return false } func containsAutomatedKeywords(email string) bool { keywords := []string{"noreply", "no-reply", "automated", "system", "admin"} email = strings.ToLower(email) for _, keyword := range keywords { if strings.Contains(email, keyword) { return true } } return false } func printSummary(recommendations CleanupRecommendations) { fmt.Printf("\n=== INBOX CLEANUP RECOMMENDATIONS ===\n\n") stats := recommendations.StorageStats fmt.Printf("šŸ“Š CURRENT STATE:\n") fmt.Printf(" Total emails: %d\n", stats.TotalEmails) fmt.Printf(" Potential for deletion: %d emails\n", stats.DeletionPotential) fmt.Printf(" Potential for archiving: %d emails\n", stats.ArchivePotential) fmt.Printf(" Total inbox reduction: %.1f%%\n\n", stats.PercentageReduction) fmt.Printf("šŸ—‘ļø SAFE TO DELETE (%d emails):\n", stats.DeletionPotential) for i, rec := range recommendations.SafeToDelete { fmt.Printf(" %d. %s (%d emails, %s risk)\n", i+1, rec.Category, rec.Count, rec.Risk) fmt.Printf(" Query: %s\n", rec.Query) } fmt.Printf("\nšŸ“¦ BULK ARCHIVE (%d emails):\n", stats.ArchivePotential) for i, rec := range recommendations.BulkArchive { fmt.Printf(" %d. %s (%d emails)\n", i+1, rec.Category, rec.Count) fmt.Printf(" Query: %s\n", rec.Query) } fmt.Printf("\nāœ‹ UNSUBSCRIBE TARGETS:\n") for i, target := range recommendations.UnsubscribeTargets { if i >= 5 { fmt.Printf(" ... and %d more (use 'detailed' output for full list)\n", len(recommendations.UnsubscribeTargets)-5) break } fmt.Printf(" %d. %s (%d emails, %s priority)\n", i+1, target.Sender, target.Count, target.Priority) } fmt.Printf("\nāš ļø NEEDS ATTENTION:\n") for i, item := range recommendations.AttentionNeeded { fmt.Printf(" %d. %s\n", i+1, item.Description) fmt.Printf(" Action: %s\n", item.Action) } fmt.Printf("\nšŸ’” NEXT STEPS:\n") fmt.Printf(" 1. Review deletion candidates (start with low-risk items)\n") fmt.Printf(" 2. Set up bulk archive operations\n") fmt.Printf(" 3. Unsubscribe from high-priority senders\n") fmt.Printf(" 4. Create Gmail filters to prevent future buildup\n") fmt.Printf(" 5. Address attention items\n\n") fmt.Printf("Use 'detailed' output format for complete Gmail queries and instructions.\n") } func printDetailed(recommendations CleanupRecommendations) { printSummary(recommendations) fmt.Printf("\n=== DETAILED CLEANUP INSTRUCTIONS ===\n\n") fmt.Printf("šŸ—‘ļø DELETION INSTRUCTIONS:\n") for i, rec := range recommendations.SafeToDelete { fmt.Printf("\n%d. %s (%s risk)\n", i+1, rec.Category, rec.Risk) fmt.Printf(" Gmail Query: %s\n", rec.Query) fmt.Printf(" Description: %s\n", rec.Description) fmt.Printf(" Estimated Count: %d emails\n", rec.Count) fmt.Printf(" Examples: %s\n", strings.Join(rec.Examples, ", ")) fmt.Printf(" Instructions:\n") fmt.Printf(" 1. Paste query into Gmail search\n") fmt.Printf(" 2. Review a few emails to confirm they're safe to delete\n") fmt.Printf(" 3. Select all → Delete\n") } fmt.Printf("\nšŸ“¦ ARCHIVE INSTRUCTIONS:\n") for i, rec := range recommendations.BulkArchive { fmt.Printf("\n%d. %s\n", i+1, rec.Category) fmt.Printf(" Gmail Query: %s\n", rec.Query) fmt.Printf(" Description: %s\n", rec.Description) fmt.Printf(" Reason: %s\n", rec.Reason) fmt.Printf(" Estimated Count: %d emails\n", rec.Count) fmt.Printf(" Instructions:\n") fmt.Printf(" 1. Paste query into Gmail search\n") fmt.Printf(" 2. Select all → Archive\n") } fmt.Printf("\nāœ‹ UNSUBSCRIBE DETAILS:\n") for i, target := range recommendations.UnsubscribeTargets { fmt.Printf("\n%d. %s (%s priority)\n", i+1, target.Sender, target.Priority) fmt.Printf(" Email Count: %d\n", target.Count) fmt.Printf(" Category: %s\n", target.Category) fmt.Printf(" Reason: %s\n", target.Reason) fmt.Printf(" Gmail Query: from:%s\n", target.Sender) } } func outputJSON(recommendations CleanupRecommendations) { encoder := json.NewEncoder(os.Stdout) encoder.SetIndent("", " ") encoder.Encode(recommendations) }