Guest User

Untitled

a guest
Feb 28th, 2018
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.48 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2. require 'net/imap'
  3.  
  4. # Source server connection info.
  5. SOURCE_HOST = 'mail.example.com'
  6. SOURCE_PORT = 993
  7. SOURCE_SSL = true
  8. SOURCE_USER = 'username'
  9. SOURCE_PASS = 'password'
  10.  
  11. # Destination server connection info.
  12. DEST_HOST = 'imap.gmail.com'
  13. DEST_PORT = 993
  14. DEST_SSL = true
  15. DEST_USER = 'user@gmail.com'
  16. DEST_PASS = 'password'
  17.  
  18. UID_BLOCK_SIZE = 1024 # max number of messages to select at once
  19.  
  20. # Mapping of source folders to destination folders. The key is the name of the
  21. # folder on the source server, the value is the name on the destination server.
  22. # Any folder not specified here will be ignored. If a destination folder does
  23. # not exist, it will be created.
  24. FOLDERS = {
  25. 'INBOX' => 'INBOX',
  26. #'sourcefolder' => 'gmailfolder'
  27. }
  28.  
  29. # Utility methods.
  30. def dd(message)
  31. puts "[#{DEST_HOST}] #{message}"
  32. end
  33.  
  34. def ds(message)
  35. puts "[#{SOURCE_HOST}] #{message}"
  36. end
  37.  
  38. def uid_fetch_block(server, uids, *args)
  39. pos = 0
  40. while pos < uids.size
  41. server.uid_fetch(uids[pos, UID_BLOCK_SIZE], *args).each { |data| yield data }
  42. pos += UID_BLOCK_SIZE
  43. end
  44. end
  45.  
  46. # Connect and log into both servers.
  47. ds 'connecting...'
  48. source = Net::IMAP.new(SOURCE_HOST, SOURCE_PORT, SOURCE_SSL)
  49.  
  50. ds 'logging in...'
  51. source.login(SOURCE_USER, SOURCE_PASS)
  52.  
  53. dd 'connecting...'
  54. dest = Net::IMAP.new(DEST_HOST, DEST_PORT, DEST_SSL)
  55.  
  56. dd 'logging in...'
  57. dest.login(DEST_USER, DEST_PASS)
  58.  
  59. # Loop through folders and copy messages.
  60. FOLDERS.each do |source_folder, dest_folder|
  61. # Open source folder in read-only mode.
  62. begin
  63. ds "selecting folder '#{source_folder}'..."
  64. source.examine(source_folder)
  65. rescue => e
  66. ds "error: select failed: #{e}"
  67. next
  68. end
  69.  
  70. # Open (or create) destination folder in read-write mode.
  71. begin
  72. dd "selecting folder '#{dest_folder}'..."
  73. dest.select(dest_folder)
  74. rescue => e
  75. begin
  76. dd "folder not found; creating..."
  77. dest.create(dest_folder)
  78. dest.select(dest_folder)
  79. rescue => ee
  80. dd "error: could not create folder: #{e}"
  81. next
  82. end
  83. end
  84.  
  85. # Build a lookup hash of all message ids present in the destination folder.
  86. dest_info = {}
  87.  
  88. dd 'analyzing existing messages...'
  89. uids = dest.uid_search(['ALL'])
  90. dd "found #{uids.length} messages"
  91. if uids.length > 0
  92. uid_fetch_block(dest, uids, ['ENVELOPE']) do |data|
  93. dest_info[data.attr['ENVELOPE'].message_id] = true
  94. end
  95. end
  96.  
  97. # Loop through all messages in the source folder.
  98. uids = source.uid_search(['ALL'])
  99. ds "found #{uids.length} messages"
  100. if uids.length > 0
  101. uid_fetch_block(source, uids, ['ENVELOPE']) do |data|
  102. mid = data.attr['ENVELOPE'].message_id
  103.  
  104. # If this message is already in the destination folder, skip it.
  105. next if dest_info[mid]
  106.  
  107. # Download the full message body from the source folder.
  108. ds "downloading message #{mid}..."
  109. msg = source.uid_fetch(data.attr['UID'], ['RFC822', 'FLAGS',
  110. 'INTERNALDATE']).first
  111.  
  112. # Append the message to the destination folder, preserving flags and
  113. # internal timestamp.
  114. dd "storing message #{mid}..."
  115. success = false
  116. begin
  117. dest.append(dest_folder, msg.attr['RFC822'], msg.attr['FLAGS'], msg.attr['INTERNALDATE'])
  118. success = true
  119. rescue Net::IMAP::NoResponseError => e
  120. puts "Got exception: #{e.message}. Retrying..."
  121. sleep 1
  122. end until success
  123.  
  124. dest.append(dest_folder, msg.attr['RFC822'], msg.attr['FLAGS'],
  125. msg.attr['INTERNALDATE'])
  126. end
  127. end
  128.  
  129. source.close
  130. dest.close
  131. end
  132.  
  133. puts 'done'
Add Comment
Please, Sign In to add comment