Googlemail-Backup mit IMAP
Wie schon erwähnt, bin ich auf der Suche nach der perfekten Lösung, meine Googlemail-E-Mails zu sichern. Und ich denke ich habe sie gefunden: ein Ruby-Script, das die Synchronisation zwischen meinem Googlemail-Account und einem zweiten IMAP-Account übernimmt. Synchronisation ist dabei vielleicht das falsche Wort, es ist eher ein Backup, was den zweiten IMAP-Account auf dem gleichen Stand wie den Googlemail-Account hält.
Die Basis für das Script kommt von Ryan Grove. Ich habe das Löschen von Nachrichten und die Ordner-Auflistung hinzugefügt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | #!/usr/bin/env ruby require 'net/imap' # Source server connection info. SOURCE_HOST = 'imap.googlemail.com' SOURCE_PORT = 993 SOURCE_SSL = true SOURCE_USER = 'EMAIL@googlemail.com' SOURCE_PASS = 'PASSWORT' # Destination server connection info. DEST_HOST = 'imap.SERVER.com' DEST_PORT = 143 DEST_SSL = false DEST_USER = 'USER' DEST_PASS = 'PASSWORT' # List of all Folder that should not be synced FOLDERS_EXCLUDE = [ '[Google Mail]', '[Google Mail]/Sent Mail', '[Google Mail]/Spam', '[Google Mail]/Trash' ] # Utility methods. def dd(message) puts "[#{DEST_HOST}] #{message}" end def ds(message) puts "[#{SOURCE_HOST}] #{message}" end # Connect and log into both servers. ds 'connecting...' source = Net::IMAP.new(SOURCE_HOST, SOURCE_PORT, SOURCE_SSL) ds 'logging in...' source.login(SOURCE_USER, SOURCE_PASS) dd 'connecting...' dest = Net::IMAP.new(DEST_HOST, DEST_PORT, DEST_SSL) dd 'logging in...' dest.login(DEST_USER, DEST_PASS) # Getting the folders to sync folders = Array.new source.list("", "%").each do |mailbox| if FOLDERS_EXCLUDE.include?(mailbox.name) == false folders << mailbox.name end if mailbox.attr.include?(Net::IMAP::NOSELECT) source.list("", "#{mailbox.name}/%").each do |mailboxChild| if FOLDERS_EXCLUDE.include?(mailboxChild.name) == false folders << mailboxChild.name end end end end #puts folders # Loop through folders and copy messages. folders.each do |foldername| # Open source folder in read-only mode. begin ds "selecting folder '#{foldername}'..." source.examine(foldername) rescue => e ds "error: select failed: #{e}" next end # Open (or create) destination folder in read-write mode. begin dd "selecting folder '#{foldername}'..." dest.select(foldername) rescue => e begin dd "folder not found; creating..." dest.create(foldername) dest.select(foldername) rescue => ee dd "error: could not create folder: #{e}" next end end # Build a lookup hash of all message ids present in the destination folder. dest_info = {} dd 'analyzing existing messages...' uids = dest.uid_search(['ALL']) if uids.length > 0 dest.uid_fetch(uids, ['ENVELOPE']).each do |data| dest_info[data.attr['ENVELOPE'].message_id] = true end end # Loop through all messages in the source folder. uids = source.uid_search(['ALL']) if uids.length > 0 source.uid_fetch(uids, ['ENVELOPE']).each do |data| mid = data.attr['ENVELOPE'].message_id # If this message is already in the destination folder, skip it. next if dest_info[mid] # Download the full message body from the source folder. ds "downloading message #{mid}..." msg = source.uid_fetch(data.attr['UID'], ['RFC822', 'FLAGS', 'INTERNALDATE']).first # Append the message to the destination folder, preserving flags and # internal timestamp. dd "storing message #{mid}..." dest.append(foldername, msg.attr['RFC822'], msg.attr['FLAGS'], msg.attr['INTERNALDATE']) end end # Build a lookup hash of all message ids present in the source folder. source_info = {} dd 'analyzing source messages...' uids = source.uid_search(['ALL']) if uids.length > 0 source.uid_fetch(uids, ['ENVELOPE']).each do |data| source_info[data.attr['ENVELOPE'].message_id] = true end end # Loop through all messages in the source folder. uids = dest.uid_search(['ALL']) if uids.length > 0 dest.uid_fetch(uids, ['ENVELOPE']).each do |data| mid = data.attr['ENVELOPE'].message_id # If this message is already in the destination folder, skip it. next if source_info[mid] # Setting flag for deletion ds "deleting message #{mid}..." dest.store(data.seqno, "+FLAGS", [:Deleted]) end end dest.expunge source.close dest.close end puts 'done' |
Kategorien: Blog | 11 Kommentare »

16.10.2008 um 11:54
[...] winnie: 31 Days of iPhone Apps, Googlemail Backup mit IMAP [...]
11.12.2008 um 14:59
Hi Winnie!
Ich habs im Cast schon kurz gehört und grad nach der heutigen BitsundSo Folge nochmal hier gelsen.
Du kannst den selben Effekt auch wunderbar mit dem Imapfilter erreichen (http://imapfilter.hellug.gr/) der auch wunderbar auf BSD läuft.
Bei mir filtert er auf dem FreeBSD Mailserver die Mails in Unterordner. Er unterstützt aber auch mehrere Mailserver. Damit ist das Backup 1 Zeile auf der Shell.
LG Marius
3.02.2009 um 22:58
Hi Winnie,
was wenn ich einen GMX Account sichern möchte, habe ich da die Möglichkeit oben GMX einzutragen. Wenn ja welchen Port muß ich wählen?
Kann man bei Google kostenlos IMAP bekommen? Kann ich mein GMX bei Google sichern?
Gruß
Filip
4.02.2009 um 13:27
Hallo Filip,
klar kannst du auch einen GMX Account mit dem Script sichern. GMX sollte den Standart-IMAP-Port 143 benutzen – ganz sicher bin ich nicht, du mußt es wohl probieren.
Wenn du dir einen Googlemail-Account holst, ist der kostenlos und du kannst sowohl IMAP, als auch POP3 benutzen. Sicherlich ist es auch möglich deine GMX-Mails auf Googlemail zu sichern. Du mußt allerdings aufpassen, weil Googlemail nach einer bestimmten Datenmenge den Account erstmal “dichtmacht” und keine Anfragen per IMAP mehr zuläßt.
-Winnie
5.02.2009 um 14:17
Hallo Winnie,
was meinst du mit: Nach einer bestimmten Datenmenge dichtmacht?
Ich habe gerade eben 1.458 Mails bei Google – entspricht 1% des Speichers.
Dann wären 100% 145.000 Mails … hmm, ein Haufen Zeugs?
Liebe Grüße
bikershrek
5.02.2009 um 15:00
@bikershrek
Mit Datenmenge ist sowas wie 1 GB gemeint und nicht die Anzahl der E-Mails. Es kann sein, dass nicht alle Mails gesynct werden können, weil sie zu viel Speicherplatz belegen.
-Winnie
6.02.2009 um 09:56
@Winnie
Hmm … mein Google Account hat 7.292 MB – den sollte erst mal einer voll bekommen – mit Mails. ;)
Lg.
bikershrek :)
21.02.2009 um 11:02
Hi!
Danke für das Script! Es scheint seinen Dienst zu verrichten – bei mir leider nur in der Inbox, denn es hat Probleme mit meinem IMAP-Server. (Es sagt, dass es keine Ordner anlegen könne) Ich nutze einen IMAP-Server, der als Pfadtrenner den . statt des / verwendet.
Ich müsste also wohl an den relevanten Stellen (beim Ziel) aus dem / ein . machen – nur kenne ich ruby leider überhaupt nicht.
Wie wäre das zu bewerkstelligen?
Danke!
21.04.2009 um 11:23
Ich habe auch das dringende Bedürfnis meine GMail-Emails nochmal seperat irgendwo zu haben.
Habe allderings einfach mein Mail.app so eingestellt, dass eingestellt, dass es alle Mails (inkl. Anhänge) ach offline verfügbar hat.
Somit sollte ich doch auch im Falle des Verlustes meines Google Accounts keine Emails verloren haben, oder?
Wo liegt nun also der Vorteil deines Skripts??
Beste Grüße
21.05.2010 um 00:44
Danke!
Ich habe gerade das Skript benutzt um meine Emails von einem Courier-IMAP-Server zu einem Cyrus-IMAP-Server umzuziehen. Das Skript hat aber meiner Meinung nach ein paar kleine Fehler. In Zeile 55 wird alles Handeln auf Ordner mit dem IMAP-Attribut “NoSelect” beschränkt. Nachdem was ich gelesen habe kann man gerade diese Ordner nicht auswählen. Ich musste die Bedeutung invertieren, damit das Skript mehr als nur den Wurzel-Ordner synchronisiert. Außerdem beachtet das Skript die Ordner-Trennzeichen-Info vom Server nicht. Der Autor geht scheinbar davon aus, dass die Ordner auf beiden Server gleich – und zwar mit “/” – getrennt werden. In meinem Fall trennt der eine Server aber mit “.” und der andere mit “/”. Und Ordner in Ordnern mag das Skript auch nicht ohne Anpassung.
Der Rest funktioniert sehr gut und ich bin erstaunt wie gut sich Ruby ließt. Das ist nämlich mein erstes mal mit Ruby :)
21.07.2010 um 16:51
@Thomas: kannst du vielleicht einen Link zu deinem veränderten Script posten damit auch andere von deinen Änderungen profitieren? Danke!