Як я можу завантажити всі електронні листи з вкладеннями з Gmail?


83

Як підключитися до Gmail і визначити, до яких повідомлень є вкладення? Потім я хочу завантажити кожне вкладення, роздрукувавши Тема: та Від: для кожного повідомлення, коли я його обробляю.


24
Цей сайт стосується отримання чітко визначених відповідей на чітко визначені питання. Моє запитання не є чітко визначеним? Зараз я шукаю чітко визначену відповідь на одній із 3 мов, якими я зазвичай користуюся.

Відповіді:


154

Важкий :-)

import email, getpass, imaplib, os

detach_dir = '.' # directory where to save attachments (default: current)
user = raw_input("Enter your GMail username:")
pwd = getpass.getpass("Enter your password: ")

# connecting to the gmail imap server
m = imaplib.IMAP4_SSL("imap.gmail.com")
m.login(user,pwd)
m.select("[Gmail]/All Mail") # here you a can choose a mail box like INBOX instead
# use m.list() to get all the mailboxes

resp, items = m.search(None, "ALL") # you could filter using the IMAP rules here (check http://www.example-code.com/csharp/imap-search-critera.asp)
items = items[0].split() # getting the mails id

for emailid in items:
    resp, data = m.fetch(emailid, "(RFC822)") # fetching the mail, "`(RFC822)`" means "get the whole stuff", but you can ask for headers only, etc
    email_body = data[0][1] # getting the mail content
    mail = email.message_from_string(email_body) # parsing the mail content to get a mail object

    #Check if any attachments at all
    if mail.get_content_maintype() != 'multipart':
        continue

    print "["+mail["From"]+"] :" + mail["Subject"]

    # we use walk to create a generator so we can iterate on the parts and forget about the recursive headach
    for part in mail.walk():
        # multipart are just containers, so we skip them
        if part.get_content_maintype() == 'multipart':
            continue

        # is this part an attachment ?
        if part.get('Content-Disposition') is None:
            continue

        filename = part.get_filename()
        counter = 1

        # if there is no filename, we create one with a counter to avoid duplicates
        if not filename:
            filename = 'part-%03d%s' % (counter, 'bin')
            counter += 1

        att_path = os.path.join(detach_dir, filename)

        #Check if its already there
        if not os.path.isfile(att_path) :
            # finally write the stuff
            fp = open(att_path, 'wb')
            fp.write(part.get_payload(decode=True))
            fp.close()

Ого! Це було щось. ;-) Але спробуйте те саме на Java, просто для розваги!

До речі, я тестував це в оболонці, тому деякі помилки, ймовірно, залишаються.

Насолоджуйтесь

РЕДАГУВАТИ:

Оскільки імена поштових скриньок можуть змінюватися з однієї країни до іншої, я рекомендую зробити m.list()та вибрати елемент у ньому раніше, m.select("the mailbox name")щоб уникнути цієї помилки:

imaplib.error: команда SEARCH незаконна у штаті AUTH, дозволена лише у штатах SELECTED


Дякую JF Написав, що wuick і брудний, ви надали йому значення :-D
e-satisfa

Це хороша відповідь. Він гине з помилкою malloc на великих вкладеннях. Python (57780) Танос: *** ММАП (розмір = 9658368)

Де в сценарії він вмирає? Я не отримую цієї помилки, але ми можемо знайти обхідний шлях.
e-satisfa

imaplib.py lib: (*** помилка: неможливо виділити регіон) помилка resp, data = m.fetch (emailid, "(RFC822)") # отримання поштового файлу "/Library/Frameworks/Python.framework/Versions /2.5/lib/python2.5/imaplib.py ", рядок 437, у типі отримання, dat = self._simple_command (ім'я, набір повідомлень, повідомлення_частин)

Якщо вам довелося б запустити це на високоактивній системі, чи було б краще обробляти кожну електронну пошту окремо або періодично всі одразу? Для обох рішень потрібна черга, але мені цікаво, яке з них було б легше масштабовано?
kari.patila

9

Я не фахівець з Perl, але те, що я знаю, це те, що GMail підтримує протоколи IMAP і POP3, 2 які є повністю стандартними і дозволяють робити саме це.

Можливо, це допоможе вам розпочати.


IMAP Я б сказав, що є більш надійним з цих двох для цілей резервного копіювання.
Kris Kumler

8
#!/usr/bin/env python
"""Save all attachments for given gmail account."""
import os, sys
from libgmail import GmailAccount

ga = GmailAccount("your.account@gmail.com", "pA$$w0Rd_")
ga.login()

# folders: inbox, starred, all, drafts, sent, spam
for thread in ga.getMessagesByFolder('all', allPages=True):
    for msg in thread:
        sys.stdout.write('.')
        if msg.attachments:
           print "\n", msg.id, msg.number, msg.subject, msg.sender
           for att in msg.attachments:
               if att.filename and att.content:
                  attdir = os.path.join(thread.id, msg.id)
                  if not os.path.isdir(attdir):
                     os.makedirs(attdir)                
                  with open(os.path.join(attdir, att.filename), 'wb') as f:
                       f.write(att.content)

неперевірений

  1. Переконайтеся, що TOS дозволяє такі сценарії, інакше ваш обліковий запис буде призупинено
  2. Можуть бути кращі варіанти: режим офлайн GMail, Thunderbird + ExtractExtensions, GmailFS, Gmail Drive тощо.


7

Погляньте на Mail :: Webmail :: Gmail :

ОТРИМАННЯ ПРИКЛАДІВ

Є два способи отримати вкладення:

1 -> Надсилаючи посилання на певний вкладення, повернене користувачем get_indv_email

# Creates an array of references to every attachment in your account
my $messages = $gmail->get_messages();
my @attachments;

foreach ( @{ $messages } ) {
    my $email = $gmail->get_indv_email( msg => $_ );
    if ( defined( $email->{ $_->{ 'id' } }->{ 'attachments' } ) ) {
        foreach ( @{ $email->{ $_->{ 'id' } }->{ 'attachments' } } ) {
            push( @attachments, $gmail->get_attachment( attachment => $_ ) );
            if ( $gmail->error() ) {
                print $gmail->error_msg();
            }
        }
    }
}

2 -> Або надіславши ідентифікатор вкладення та ідентифікатор повідомлення

#retrieve specific attachment
my $msgid = 'F000000000';
my $attachid = '0.1';
my $attach_ref = $gmail->get_attachment( attid => $attachid, msgid => $msgid );

(Повертає посилання на скаляр, що містить дані з вкладення.)


4

У gmail ви можете відфільтрувати "has: attachment", використовувати його для визначення повідомлень, які ви повинні отримувати під час тестування. Зверніть увагу, що це, здається, надає як повідомлення із вкладеними файлами (відображається значок скріпки), так і вбудовані вкладені зображення (скріпка не відображається).

Не існує API Gmail, тому IMAP або POP - це ваші єдині реальні варіанти. JavaMail API може бути якийсь - то допомоги, а також цей дуже лаконічній статті про завантаженні додатків з використанням протоколу IMAP Perl . Деякі попередні запитання тут на SO також можуть допомогти.

Цей приклад PHP також може допомогти. На жаль, з того, що я бачу, інформація imap_header не містить інформації про вкладення, тому завантаження тіла потрібно, щоб побачити поле X-Attachment-Id. (хтось, будь ласка, доведіть мені помилку).


3

Якщо хтось із вас оновився до python 3.3, я взяв сценарій 2.7 ТУТ і оновив його до 3.3. Також виправлено деякі проблеми із способом повернення інформації gmail.

# Something in lines of http://stackoverflow.com/questions/348630/how-can-i-download-all-emails-with-attachments-from-gmail
# Make sure you have IMAP enabled in your gmail settings.
# Right now it won't download same file name twice even if their contents are different.
# Gmail as of now returns in bytes but just in case they go back to string this line is left here.

import email
import getpass, imaplib
import os
import sys
import time

detach_dir = '.'
if 'attachments' not in os.listdir(detach_dir):
    os.mkdir('attachments')

userName = input('Enter your GMail username:\n')
passwd = getpass.getpass('Enter your password:\n')


try:
    imapSession = imaplib.IMAP4_SSL('imap.gmail.com',993)
    typ, accountDetails = imapSession.login(userName, passwd)
    if typ != 'OK':
        print ('Not able to sign in!')
        raise

    imapSession.select('Inbox')
    typ, data = imapSession.search(None, 'ALL')
    if typ != 'OK':
        print ('Error searching Inbox.')
        raise

    # Iterating over all emails
    for msgId in data[0].split():
        typ, messageParts = imapSession.fetch(msgId, '(RFC822)')

        if typ != 'OK':
            print ('Error fetching mail.')
            raise 

        #print(type(emailBody))
        emailBody = messageParts[0][1]
        #mail = email.message_from_string(emailBody)
        mail = email.message_from_bytes(emailBody)

        for part in mail.walk():
            #print (part)
            if part.get_content_maintype() == 'multipart':
                # print part.as_string()
                continue
            if part.get('Content-Disposition') is None:
                # print part.as_string()
                continue

            fileName = part.get_filename()

            if bool(fileName):
                filePath = os.path.join(detach_dir, 'attachments', fileName)
                if not os.path.isfile(filePath) :
                    print (fileName)
                    fp = open(filePath, 'wb')
                    fp.write(part.get_payload(decode=True))
                    fp.close()

    imapSession.close()
    imapSession.logout()

except :
    print ('Not able to download all attachments.')
    time.sleep(3)


2
/*based on http://www.codejava.net/java-ee/javamail/using-javamail-for-searching-e-mail-messages*/
package getMailsWithAtt;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeBodyPart;
import javax.mail.search.AndTerm;
import javax.mail.search.SearchTerm;
import javax.mail.search.ReceivedDateTerm;
import javax.mail.search.ComparisonTerm;

public class EmailReader {
    private String saveDirectory;

    /**
     * Sets the directory where attached files will be stored.
     * 
     * @param dir
     *            absolute path of the directory
     */
    public void setSaveDirectory(String dir) {
        this.saveDirectory = dir;
    }

    /**
     * Downloads new messages and saves attachments to disk if any.
     * 
     * @param host
     * @param port
     * @param userName
     * @param password
     * @throws IOException
     */
    public void downloadEmailAttachments(String host, String port,
            String userName, String password, Date startDate, Date endDate) {
        Properties props = System.getProperties();
        props.setProperty("mail.store.protocol", "imaps");
        try {
            Session session = Session.getDefaultInstance(props, null);
            Store store = session.getStore("imaps");
            store.connect("imap.gmail.com", userName, password);
            // ...
            Folder inbox = store.getFolder("INBOX");
            inbox.open(Folder.READ_ONLY);
            SearchTerm olderThan = new ReceivedDateTerm (ComparisonTerm.LT, startDate);
            SearchTerm newerThan = new ReceivedDateTerm (ComparisonTerm.GT, endDate);
            SearchTerm andTerm = new AndTerm(olderThan, newerThan);
            //Message[] arrayMessages = inbox.getMessages(); <--get all messages
            Message[] arrayMessages = inbox.search(andTerm);
            for (int i = arrayMessages.length; i > 0; i--) { //from newer to older
                Message msg = arrayMessages[i-1];
                Address[] fromAddress = msg.getFrom();
                String from = fromAddress[0].toString();
                String subject = msg.getSubject();
                String sentDate = msg.getSentDate().toString();
                String receivedDate = msg.getReceivedDate().toString();

                String contentType = msg.getContentType();
                String messageContent = "";

                // store attachment file name, separated by comma
                String attachFiles = "";

                if (contentType.contains("multipart")) {
                    // content may contain attachments
                    Multipart multiPart = (Multipart) msg.getContent();
                    int numberOfParts = multiPart.getCount();
                    for (int partCount = 0; partCount < numberOfParts; partCount++) {
                        MimeBodyPart part = (MimeBodyPart) multiPart
                                .getBodyPart(partCount);
                        if (Part.ATTACHMENT.equalsIgnoreCase(part
                                .getDisposition())) {
                            // this part is attachment
                            String fileName = part.getFileName();
                            attachFiles += fileName + ", ";
                            part.saveFile(saveDirectory + File.separator + fileName);
                        } else {
                            // this part may be the message content
                            messageContent = part.getContent().toString();
                        }
                    }
                    if (attachFiles.length() > 1) {
                        attachFiles = attachFiles.substring(0,
                                attachFiles.length() - 2);
                    }
                } else if (contentType.contains("text/plain")
                        || contentType.contains("text/html")) {
                    Object content = msg.getContent();
                    if (content != null) {
                        messageContent = content.toString();
                    }
                }

                // print out details of each message
                System.out.println("Message #" + (i + 1) + ":");
                System.out.println("\t From: " + from);
                System.out.println("\t Subject: " + subject);
                System.out.println("\t Received: " + sentDate);
                System.out.println("\t Message: " + messageContent);
                System.out.println("\t Attachments: " + attachFiles);
            }

            // disconnect
            inbox.close(false);
            store.close();

        } catch (NoSuchProviderException e) {
            e.printStackTrace();
            System.exit(1);
        } catch (MessagingException e) {
            e.printStackTrace();
            System.exit(2);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Runs this program with Gmail POP3 server
     * @throws ParseException 
     */
    public static void main(String[] args) throws ParseException {
        String host = "pop.gmail.com";
        String port = "995";
        String userName = "user@gmail.com";
        String password = "pass";
        Date startDate = new SimpleDateFormat("yyyy-MM-dd").parse("2014-06-30");
        Date endDate = new SimpleDateFormat("yyyy-MM-dd").parse("2014-06-01");
        String saveDirectory = "C:\\Temp";

        EmailReader receiver = new EmailReader();
        receiver.setSaveDirectory(saveDirectory);
        receiver.downloadEmailAttachments(host, port, userName, password,startDate,endDate);

    }
}

Залежність Maven:

<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.5.1</version>
</dependency>

@jechaviz, я отримую невідомий виняток хоста, будь ласка, будь ласка, допоможіть
Рахул Сінгх

1

Оскільки Gmail підтримує стандартні протоколи POP та IMAP, будь-яка платформа, інструмент, програма, компонент або API, що забезпечують клієнтську сторону будь-якого протоколу, повинна працювати.

Я пропоную здійснити пошук у Google для вашої улюбленої мови / платформи (наприклад, "python"), плюс "pop", плюс "imap", плюс, можливо, "з відкритим кодом", плюс, можливо, "завантажити" або "переглянути", і подивитися Ви отримуєте варіанти.

Існує безліч безкоштовних додатків та компонентів, виберіть кілька, які здаються гідними, перевірте відгуки, а потім завантажте та насолоджуйтесь.


1

Ви повинні усвідомлювати той факт, що вам потрібен SSL для підключення до GMail (як для POP3, так і для IMAP - це, звичайно, справедливо і для їх SMTP-серверів, крім порту 25, але це вже інша історія).


1

Ось те, що я написав, щоб завантажити свої банківські виписки в Groovy (динамічна мова для платформи Java).

import javax.mail.*
import java.util.Properties

String  gmailServer
int gmailPort
def user, password, LIMIT
def inboxFolder, root, StartDate, EndDate


//    Downloads all attachments from a gmail mail box as per some criteria
//    to a specific folder
//    Based on code from
//    http://agileice.blogspot.com/2008/10/using-groovy-to-connect-to-gmail.html
//    http://stackoverflow.com/questions/155504/download-mail-attachment-with-java
//
//    Requires: 
//        java mail jars in the class path (mail.jar and activation.jar)
//        openssl, with gmail certificate added to java keystore (see agileice blog)
//        
//    further improvement: maybe findAll could be used to filter messages
//    subject could be added as another criteria
////////////////////// <CONFIGURATION> //////////////////////
// Maximm number of emails to access in case parameter range is too high
LIMIT = 10000

// gmail credentials
gmailServer = "imap.gmail.com"
gmailPort = 993

user = "gmailuser@gmail.com"
password = "gmailpassword"

// gmail label, or "INBOX" for inbox
inboxFolder = "finance"

// local file system where the attachment files need to be stored
root = "D:\\AttachmentStore" 

// date range dd-mm-yyyy
StartDate= "31-12-2009"
EndDate = "1-6-2010" 
////////////////////// </CONFIGURATION> //////////////////////

StartDate = Date.parse("dd-MM-yyyy", StartDate)
EndDate = Date.parse("dd-MM-yyyy", EndDate)

Properties props = new Properties();
props.setProperty("mail.store.protocol", "imaps");
props.setProperty("mail.imaps.host", gmailServer);
props.setProperty("mail.imaps.port", gmailPort.toString());
props.setProperty("mail.imaps.partialfetch", "false");

def session = javax.mail.Session.getDefaultInstance(props,null)
def store = session.getStore("imaps")

store.connect(gmailServer, user, password)

int i = 0;
def folder = store.getFolder(inboxFolder)

folder.open(Folder.READ_ONLY)

for(def msg : folder.messages) {

     //if (msg.subject?.contains("bank Statement"))
     println "[$i] From: ${msg.from} Subject: ${msg.subject} -- Received: ${msg.receivedDate}"

     if (msg.receivedDate <  StartDate || msg.receivedDate > EndDate) {
         println "Ignoring due to date range"
         continue
     }


     if (msg.content instanceof Multipart) {
         Multipart mp = (Multipart)msg.content;

         for (int j=0; j < mp.count; j++) {

             Part part = mp.getBodyPart(j);

             println " ---- ${part.fileName} ---- ${part.disposition}"

             if (part.disposition?.equalsIgnoreCase(Part.ATTACHMENT)) {

                 if (part.content) {

                     def name = msg.receivedDate.format("yyyy_MM_dd") + " " + part.fileName
                     println "Saving file to $name"

                     def f = new File(root, name)

                     //f << part.content
                     try {
                         if (!f.exists())
                             f << part.content
                     }
                     catch (Exception e) {
                         println "*** Error *** $e" 
                     }
                 }
                 else {
                    println "NO Content Found!!"
                 }
             }
         }
     }

     if (i++ > LIMIT)
         break;

}


0

Для Java ви знайдете G4J для використання. Це набір API для взаємодії з Google Mail через Java (скріншот на домашній сторінці - це демонстраційний поштовий клієнт, побудований навколо цього)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.