Commit Graph

61 Commits

Author SHA1 Message Date
Javier Callico
e14e6915b0 Add comprehensive tests for IMAP utilities and compression support
- Introduced tests for `imap_common.py` covering environment variable verification, IMAP connection handling, folder name normalization, MIME header decoding, message details extraction, duplicate detection, filename sanitization, and trash folder detection.
- Added tests for `imap_compress.py` to validate the functionality of the `_CompressedSocket` wrapper, ensuring data compression and decompression works as expected.
- Implemented integration tests to verify that compression is enabled during IMAP connection setup.
2026-02-15 08:36:58 -05:00
Javier Callico
2498c3e837 Add comprehensive tests for IMAP email restoration functionality
- Implement tests for loading labels manifest, including both old and new formats.
- Add tests for extracting flags from the manifest.
- Create tests for parsing .eml files, including edge cases.
- Develop tests for retrieving .eml files from a directory.
- Validate configuration settings and handle missing credentials.
- Integrate tests for restoring emails from a backup, including Gmail mode and deletion of orphaned emails.
- Test progress caching and backup folder discovery.
- Ensure robust handling of email labels and flags during restoration.
- Verify that the restore process correctly interacts with a mock IMAP server.
2026-02-14 17:59:14 -05:00
Javier Callico
cbf09c5348
Update installation instructions in README.md to include PyPI installation and macOS recommendations (#39) 2026-02-14 17:19:12 -05:00
Javier Callico
6e0b338bf2
Minor UX improvements and cleanup (#38)
* Enhance error handling and user interruption responses across multiple scripts

* Refactor error handling tests to improve connection simulation and patching

* Remove comments about exception propagation in main functions across multiple scripts

* Update versioning and add version argument to scripts for better tracking
2026-02-14 16:52:53 -05:00
Nathan Moinvaziri
0d1bdadf5e
Add Contacts to Exchange skip folders (#36)
The Contacts folder contains proprietary Exchange data that causes
errors during IMAP backup, similar to the existing Suggested Contacts
entry.
2026-02-13 17:06:19 -05:00
Nathan Moinvaziri
ba96004e38
Add IMAP compression support to connection setup (#33) 2026-02-13 17:04:21 -05:00
Nathan Moinvaziri
02c70a1e5c
Prevent redundant IMAP commands (#32)
* Pre-fetch folder Message-IDs for migrate and restore scripts

Both scripts were issuing an IMAP SELECT + SEARCH for every single email
to check for duplicates. Now we fetch all Message-IDs per folder once
via a shared load_folder_msg_ids() in imap_common and use in-memory set
lookups. This also applies to Gmail label folders, cutting IMAP
round-trips dramatically.

* Skip redundant folder CREATE calls during migration and restore

load_folder_msg_ids() already creates each folder on first access, so
the per-email CREATE in upload_email(), the per-label CREATE in
append_email(), and the batch-level ensure_folder_exists + select in
process_batch() were issuing unnecessary IMAP commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove exception suppression and propagate auth errors in IMAP ops

* Remove duplicate checking from upload_email function

* Simplify destination connection handling in process_batch

* Rename source_msg_ids to cached_dest_msg_ids for clarity

* Refactor destination message ID caching logic in migration code

* Skip duplicate filtering during full restore for flag/label sync

* Replace mock-based tests with e2e tests for load_folder_msg_ids

Swap 6 mock-heavy unit tests for 4 e2e tests using the mock IMAP server,
testing actual input/output behavior (fetch, cache, empty folder, folder
creation) instead of internal implementation details.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 06:46:04 -05:00
Javier Callico
c6a568857f
Add connection proxy wrapper for IMAP retry functionality (#34) 2026-02-10 11:06:18 -05:00
Nathan Moinvaziri
11bcbb311f
Add error handling for IMAP STORE and APPEND operations (#30) 2026-02-08 20:30:36 -05:00
Javier Callico
b19e71c965
Publishing Python package to PyPI (#29)
* Add GitHub Actions workflow for publishing Python package to PyPI and update pyproject.toml with project metadata

* Bump version to 1.0.0 in pyproject.toml
2026-02-08 14:40:30 -05:00
Javier Callico
13db9b2a30
Ensure migration resumption functionality with cache tracking (#28)
* Implement migration resumption functionality with cache tracking and tests

* Remove unused pytest import from migration resumption tests
2026-02-08 14:16:01 -05:00
Javier Callico
f0961c14ea Remove MonkeyPatch from tests. (#26)
* Remove MonkeyPatch from tests.

- Minimal changes to default values on production scripts to allow for overrides from tests.

-  Itroduces a minimal OAuth2 mock server implemented in Python.
The server can handle GET and POST requests for OpenID configuration and token
retrieval for Google and Microsoft, respectively. It is designed to facilitate
testing without the need for actual OAuth providers.

* Add tests for custom authority URL and enhance fetch_json_https functionality

* Add tests for scheme parsing and invalid host URL handling in get_imap_connection

* Add copilot instructions for running checks and writing tests
2026-02-08 12:04:08 -05:00
Nathan Moinvaziri
cd05a22d4b Share common functionality among scripts (#25)
* Move sync_flags_on_existing to imap_common shared module

Both migrate and restore scripts had near-identical implementations
of flag syncing. The unified version combines the best of each:
regex-based flag parsing, case-insensitive comparison, and batch
flag storage in a single IMAP call.

* Move delete_orphan_emails to imap_common shared module

The restore script had its own inline batch-fetching implementation
that duplicated get_uid_to_message_id_map. Both scripts now use
the same shared function, which also gives restore the larger
batch size (500 vs 100) for faster Message-ID lookups.

* Move thread-local connection management to imap_session

All three scripts had their own get_thread_connection(s) wrappers
around the same ensure_connection + getattr/setattr pattern. Also
removes dead tuple-normalization code from the backup script.

* Move manifest loading to shared load_manifest in imap_common

Backup and restore each had their own load_labels_manifest with
minor differences (logging vs silent). The shared version takes
a filename parameter and handles both labels and flags manifests.
Also removes the now-unused json import from restore.

* Remove duplicate label_to_folder from restore script

The restore script had its own copy of label_to_folder identical
to provider_gmail's version. Callers now use the canonical
implementation, and 7 duplicate tests are removed since
test_provider_gmail already covers every case.

* Print warning when failing to mark deleted in folder

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Improve example filename

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update comment about sync_flags_on_existing

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Extract pre-filter logic into dedicated functions

Moves duplicate-filtering loops out of migrate_folder and
restore_folder into pre_filter_uids and pre_filter_eml_files
respectively, reducing inline complexity in both orchestrators.

* Move Gmail target folder resolution to provider_gmail.resolve_target

Both migrate and restore had identical logic to pick a primary
target folder from Gmail labels and collect remaining labels.
Consolidated into a shared function in provider_gmail.

* Add tests for resolve_target function in Gmail provider

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-08 09:28:49 -05:00
Nathan Moinvaziri
9dca673e0f Add shared helpers for OAuth2 setup and IMAP config building (#24)
* Add shared helpers for OAuth2 setup and IMAP config building

Introduces acquire_token(), auth_description(), and build_imap_conf() so
each script delegates provider detection, token acquisition, error handling,
and conf dict assembly to a single implementation instead of duplicating it
inline.

* Add comprehensive tests for OAuth2 token acquisition and IMAP config
2026-02-08 09:26:42 -05:00
Javier Callico
dd5251f55d Enhance migrate script with restore cache, plus cleanup for code and tests (#23)
* Implement incremental migration with caching support and add tests for cache behavior. Cleanup for duplicated logic.

* Rewrite tests for main scripts to use end to end testing with data setup instead of mocking.

* Fix linting issues.

* Fix SEARCH response handling in MockIMAPHandler to return empty response when no results are found

* Refactor SEARCH command handling in MockIMAPHandler to streamline response generation for ALL queries and remove redundant code.

* Add cache directory creation in load_progress_cache with logging for failures

* Improve cache hit detection in process_single_uid to handle locking for existing destination message IDs

* Add tests for imap_common functions and enhance email parsing in restore_imap_emails

* Refactor test_backup_folder_discovery to create a parent directory for unreadable path

* Add tests for Gmail mode fallback folder and dest-delete functionality in restore_imap_emails

* Add tests for cache behavior and error handling in migration process
2026-02-07 19:29:21 -05:00
Nathan Moinvaziri
f53955a9bb Split provider implementations into dedicated modules (#22)
* Exclude deleted messages from duplicate detection

Adds UNDELETED filter to message_exists_in_folder so messages pending
expunge don't block uploads of fresh copies. This allows re-uploading
messages that were deleted but not yet expunged from the mailbox.

* Skip Exchange system folders during backup

Adds EXCHANGE_SKIP_FOLDERS constant to exclude Suggested Contacts and
Calendar which often contain proprietary data returning errors via IMAP.
These folders are exposed by Exchange but not reliably accessible.

* Split provider implementations into dedicated modules

Extracts Microsoft/Google OAuth2 and Gmail/Exchange IMAP logic into separate modules (oauth2_microsoft, oauth2_google, provider_gmail, provider_exchange). Creates one test file per module following single responsibility principle.

* Refresh OAuth2 token before initial folder select

Ensures token is refreshed before the initial select() and search() calls
in get_message_info_in_folder_with_conf, preventing auth failures at
function entry that would cause incomplete manifests.

* Add comment explaining OAuth2 token caching behavior

Clarifies that the OAuth2 provider implementations (MSAL, google-auth)
use internal caching and only contact the server when refresh is needed.

* Re-raise auth errors in build_gmail_label_index

Allows callers to handle OAuth2 token expiration and reconnection
instead of silently producing incomplete label indexes. Non-auth
errors continue to be handled gracefully.

* Log warning when copy-to-trash fails during migration

Replaces silent exception handling with a warning message so users
know when trash copy operations fail. The message was previously
deleted without being copied to trash.

* Reorder imports alphabetically in Python files
2026-02-07 08:45:21 -05:00
Nathan Moinvaziri
e932190618 Add imap_session module for centralized OAuth2 refresh (#21)
* Add .claude to gitignore

* Add imap_session module for centralized OAuth2 refresh

Create new imap_session.py module that combines imap_common and
imap_oauth2 for unified session management:

- ensure_connection(): Refreshes OAuth2 token and ensures connection health
- ensure_folder_session(): Ensures connection AND folder selection

Updated backup, migrate, and restore scripts to use the new module,
simplifying the proactive token refresh pattern in process_batch
functions.

* Move is_token_expired_error to imap_oauth2 module

Relocates the OAuth2 token expiration detection function to the oauth2-specific module where it logically belongs.

* Add retry logic for auth errors during email processing

Extract single-UID processing into dedicated functions with retry capability
for recoverable authentication failures. Broadens auth error detection beyond
token expiration to include session loss and authentication failures.

* Cache Microsoft tenant discovery results

Avoids repeated OpenID Connect discovery requests for the same email domain
during OAuth2 authentication flows. Normalizes domain to lowercase for
consistent cache keys.

* Add tests for is_token_expired_error and is_auth_error

Covers token expiration, session invalidation, and authentication failure
detection with case-insensitive matching verification. Ensures non-auth
errors like connection and timeout issues are correctly excluded.

* Add tests for imap_session module

Covers ensure_connection and ensure_folder_session functions including
OAuth2 token refresh, folder selection, and error handling scenarios.
Verifies connection change detection triggers folder re-selection.

* Add tests for auth error re-raising in get_message_ids_in_folder

Verifies that authentication errors are propagated to callers for
reconnection handling while non-auth errors return empty results.
Clarifies test names to distinguish error handling behaviors.
2026-02-06 13:26:44 -05:00
Nathan Moinvaziri
8c49bc7c48 Refactor IMAP connection handling with proactive OAuth2 refresh (#8)
* Refactor IMAP connection handling with proactive OAuth2 refresh
* Extract OAuth2 token refresh and connection logic into shared function
* Fix restore connection lifecycle and document exception handling
2026-02-02 19:40:39 -05:00
Javier Callico
7e853bdf27 Implement incremental restore with full restore option via restore cache. (#12)
* Implement incremental restore with full restore option and progress caching

* Refactor restore cache documentation and simplify cache path retrieval

* Add progress recording functionality for incremental restores

* Refactor email folder handling by introducing helper functions for folder creation and email appending

* Normalize flags format in append_email function for consistency

* Remove unnecessary blank line before get_labels_from_manifest function

* Enhance cache persistence with logging and error handling in save_dest_index_cache

* Add future annotations import for type hinting support

* Update src/restore_imap_emails.py

When applying Gmail labels, emails uploaded to label folders are not recorded in the progress cache. This means on subsequent incremental restore runs, the code will need to check the server again for these label folders even though the emails were just uploaded. Consider calling restore_cache.record_progress after successfully appending to a label folder (after line 514) to cache the Message-ID for that label folder as well.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/restore_cache.py

The condition for saving the cache will trigger a save based on the time threshold even when there are no pending updates (pending = 0). This can result in unnecessary disk writes. Consider adding a check to skip saving if there are no pending updates: force or (pending > 0 and (pending >= _MIN_PENDING_UPDATES_BEFORE_SAVE or (now - last_saved) >= _MIN_SECONDS_BETWEEN_SAVES)). This way, the cache is only saved when there are actually updates to persist, unless force=True.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/restore_imap_emails.py

'except' clause does nothing but pass and there is no explanatory comment.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Refactor condition in maybe_save_dest_index_cache for clarity

* [WIP] WIP Address feedback on incremental and full restore implementation (#13)

* Initial plan

* Optimize add_cached_message_id for O(1) lookups using set

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* Cache set at entry level to avoid O(n) set construction on each add

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* Move copy import to top of file per Python conventions

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* Improve code style: condense comments and docstring

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* Add batch Message-ID fetching for faster duplicate detection (#9)

* Add batch Message-ID fetching for faster duplicate detection

* Remove duplicate get_message_ids_in_folder in migrate_imap_emails

* Optimize orphan email deletion by reusing existing UID mappings

* Remove unused get_msg_details function and related test code

* Update src/restore_imap_emails.py

The call to restore_cache.record_progress is missing required keyword arguments. The function signature requires parameters like existing_dest_msg_ids, existing_dest_msg_ids_lock, progress_cache_path, progress_cache_data, progress_cache_lock, dest_host, and dest_user. This call should match the pattern used at line 456-467 where all required parameters are properly passed as keyword arguments.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/imap_common.py

The docstring states that the flags parameter is "Passed through to imaplib.IMAP4.append unchanged", but this is inaccurate. The function actually normalizes the flags by wrapping them in parentheses if they aren't already (lines 99-106). The docstring should be updated to reflect that the function normalizes flags to ensure they are in the correct IMAP format with parentheses.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add unit tests for ensure_folder_exists and append_email helper functions (#14)

* Initial plan

* Add comprehensive unit tests for ensure_folder_exists and append_email

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* Refactor folder existence checks to use imap_common.ensure_folder_exists directly

* Initial plan (#15)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* Refactor process_restore_batch to improve argument clarity for restore_cache.record_progress

* Update src/imap_common.py

The append_email function catches all exceptions and returns False, but this makes it impossible for callers to distinguish between legitimate duplicate detection (email already exists) and actual errors (network failure, server error, etc.). Consider either raising exceptions for actual errors while returning False only for duplicates, or returning a more informative result (e.g., a tuple with status and reason, or an enum). This would allow restore_imap_emails.py to only record progress when emails are confirmed to be on the server.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Refactor test_append_exception to propagate exceptions for better error handling

* Update src/imap_common.py

The append_email function does not handle exceptions from imap_conn.append(). If the append call fails with an exception (e.g., connection error, permission error), the exception will propagate to the caller instead of returning False. This is inconsistent with the documented behavior that callers expect a boolean return value to indicate success or failure. The function should wrap the append call in a try-except block and return False on exception.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* [WIP] Address feedback on incremental restore implementation (#16)

* Initial plan

* Fix: Check append_email return value before recording progress for label application

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* Add test to verify append_email return value is checked before recording progress

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* Improve error message to clarify retry behavior for failed label applications

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* [WIP] Address feedback on incremental restore implementation (#17)

* Initial plan

* Fix progress recording for failed uploads with three-state result enum

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* Clean up whitespace and simplify labels manifest definition in tests

* [WIP] Fix incremental restore return type consistency (#19)

* Initial plan

* Fix return type annotation for save_dest_index_cache to bool

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* [WIP] Work in progress on incremental restore feedback (#20)

* Initial plan

* Fix label folder progress tracking to use correct message ID set

Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>

* Refactor conditional statement for clarity in process_restore_batch function

* Remove exception handling in append_email function for cleaner flow

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JCallico <335565+JCallico@users.noreply.github.com>
Co-authored-by: Nathan Moinvaziri <nathan@nathanm.com>
2026-02-01 15:17:37 -05:00
Nathan Moinvaziri
68c741913b Add batch Message-ID fetching for faster duplicate detection (#9)
* Add batch Message-ID fetching for faster duplicate detection

* Remove duplicate get_message_ids_in_folder in migrate_imap_emails

* Optimize orphan email deletion by reusing existing UID mappings

* Remove unused get_msg_details function and related test code
2026-02-01 14:01:34 -05:00
Nathan Moinvaziri
c5db4628fc Clean up Message-ID extraction to use BytesParser in common module (#10)
* Clean up Message-ID extraction to use BytesParser in common module

* Enhance Message-ID extraction to handle header continuation lines for consistent output

* Decode message id consistently everywhere

* Clean up decode_mime_header function

* Added back missing parse_message_id_from_bytes.

---------

Co-authored-by: Javier Callico <jcallico@callicode.com>
2026-02-01 12:36:24 -05:00
Javier Callico
5f7ec8994e Remove unused password variables from main function for OAuth2 integration 2026-01-31 20:32:59 -08:00
Javier Callico
6ff0d336d9 Update README.md to reflect Python 3.9+ as the minimum requirement 2026-01-31 20:32:59 -08:00
Javier Callico
14cb45c398 Fix for Python 3.9.25 error. 2026-01-31 20:32:59 -08:00
Javier Callico
798a86e2df Fix for issue: [B310:blacklist] Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected.
Severity: Medium   Confidence: High
   CWE: CWE-22 (https://cwe.mitre.org/data/definitions/22.html)
   More Info: https://bandit.readthedocs.io/en/1.9.3/blacklists/blacklist_calls.html#b310-urllib-urlopen
   Location: src/imap_oauth2.py:52:13
2026-01-31 20:32:59 -08:00
Javier Callico
c3e36fa31c Update OAuth2 argument names in scripts and documentation for consistency 2026-01-31 20:32:59 -08:00
Javier Callico
7ea0991930 Refactor authentication handling and improve documentation for IMAP email migration scripts
- Updated README.md to clarify authentication options, including OAuth2 support.
- Modified backup_imap_emails.py to support OAuth2 credentials alongside traditional password authentication.
- Enhanced compare_imap_folders.py to conditionally require IMAP credentials based on local path usage.
- Updated count_imap_emails.py to improve argument parsing and error handling for missing credentials.
- Refactored migrate_imap_emails.py to streamline authentication logic and improve error messages.
- Enhanced restore_imap_emails.py to support OAuth2 and improve validation for required fields.
- Updated test cases across various modules to reflect changes in error handling and authentication requirements.
- Adjusted test configurations to ensure consistent exit codes for missing credentials.
2026-01-31 20:32:59 -08:00
Nathan Moinvaziri
06666529ee Add Microsoft/Google OAuth2 authentication support for IMAP 2026-01-31 20:32:59 -08:00
Javier Callico
7a03dad6ff Enhance email processing by adding header-only parsing for Message-ID and Subject from raw message bytes 2026-01-31 10:20:04 -05:00
Javier Callico
1ab1946603 Update migration scripts to replace '--delete' with '--src-delete' for source deletion 2026-01-31 09:57:47 -05:00
Javier Callico
62d020bc82 Update Gmail restore logic to use 'Restored/Unlabeled' for emails without usable labels 2026-01-31 09:52:27 -05:00
Javier Callico
124dcde614 Add support for Gmail mode and flag preservation in migration scripts
- Implement Gmail mode to migrate only "[Gmail]/All Mail" and apply labels.
- Introduce flag preservation feature to sync IMAP flags during migration.
- Enhance tests to cover new Gmail mode and flag preservation functionality.
2026-01-31 09:44:44 -05:00
Javier Callico
091e8121ed Update usage examples in README and scripts to include host and password parameters 2026-01-31 09:18:39 -05:00
Javier Callico
58ac50f54d Enhance README and scripts to support local backup folder comparisons and counting
- Updated README.md to include instructions for comparing IMAP accounts with local backup folders and counting emails in local backups.
- Modified compare_imap_folders.py to allow comparisons between IMAP accounts and local backup folders.
- Enhanced count_imap_emails.py to count emails from local backup folders.
- Added tests for local folder comparisons and counting in test_compare_imap_folders.py and test_count_imap_emails.py.
2026-01-31 09:12:10 -05:00
Javier Callico
04ed2f8ba8 Refactor migrate_folder call to resolve linting issue. 2026-01-31 08:56:10 -05:00
Javier Callico
2952f79be4 Centralize IMAP/Gmail constants and resolve linting errors. 2026-01-31 08:51:54 -05:00
Javier Callico
a17dc5b95d Merge pull request #4 from nmoinvaz/fix/select-folders
Replace manual folder listing with list_selectable_folders utility
2026-01-31 08:28:07 -05:00
Javier Callico
7dc17accda Merge pull request #6 from nmoinvaz/fix/dup-detection
Fix duplicate detection failing with iCloud IMAP
2026-01-31 08:15:52 -05:00
Nathan Moinvaziri
1fc5e13e9d Fix duplicate detection failing with iCloud IMAP
Match on Message-ID only instead of requiring both Message-ID
and exact RFC822.SIZE, which fails when servers modify messages
on storage.
2026-01-28 20:06:30 -08:00
Nathan Moinvaziri
ed52587077 Replace manual folder listing with list_selectable_folders utility
Easily exclude \NoSelect folders and folders whose status is not OK.
2026-01-28 19:12:09 -08:00
Javier Callico
927fff17c7 feat: Add delete destination functionality to sync emails between source and destination (IMAP server or local folder).
- Implemented the ability to delete orphan emails from the destination server that are not present in the local backup.
- Introduced new environment variables and command-line arguments to control the deletion behavior.
- Enhanced the restore process to check for and delete orphan emails if the DEST_DELETE option is enabled.
- Added tests to verify the correct behavior of the new deletion functionality in both backup and restore scripts.
- Updated the mock IMAP server to handle fetching of emails based on UID and improved response handling for header fields.
2026-01-28 19:48:43 -05:00
Javier Callico
965b327332 Fix print statement formatting for apply flags in main function 2026-01-28 18:34:11 -05:00
Javier Callico
127aad7b7f Fix print statement formatting for apply flags in main function 2026-01-28 18:32:55 -05:00
Javier Callico
c3a26c30bf Implement email restoration functionality with Gmail labels support
- Added restore_imap_emails.py for restoring emails from local backups to IMAP accounts.
- Implemented loading of labels and flags from a manifest file.
- Added functionality to upload emails while preserving original dates and applying Gmail labels.
- Introduced multithreading for efficient email uploads.
- Created unit tests for email parsing, restoration, and configuration validation.
- Enhanced existing tests for Gmail labels preservation in backup process.
2026-01-28 18:31:19 -05:00
Javier Callico
2c230dcf64 Implement Gmail labels preservation feature and update tests 2026-01-26 19:41:18 -05:00
Javier Callico
bfac175c0b Refactor error handling tests for IMAP operations to improve readability and consistency 2026-01-25 12:43:47 -05:00
Javier Callico
94ea94adc8 Add comprehensive error handling tests for IMAP email operations 2026-01-25 12:42:45 -05:00
Javier Callico
4f38a5f108 Add Codecov badge to README.md for test coverage visibility 2026-01-25 12:18:35 -05:00
Javier Callico
7b4643a641 Enhance CI configuration to include JUnit XML report generation and upload test results to Codecov 2026-01-25 12:14:34 -05:00
Javier Callico
7711b82924 Add workflow_dispatch trigger to CI configuration 2026-01-25 12:08:48 -05:00