Làm cách nào để tải xuống tất cả các email có tệp đính kèm từ Gmail?


83

Làm cách nào để kết nối với Gmail và xác định thư nào có tệp đính kèm? Sau đó, tôi muốn tải xuống từng tệp đính kèm, in ra Chủ đề: và Từ: cho mỗi thư khi tôi xử lý nó.


24
Trang web này là về việc nhận được câu trả lời rõ ràng cho các câu hỏi được xác định rõ ràng. Có phải câu hỏi của tôi không được xác định rõ? Bây giờ tôi đang tìm kiếm một câu trả lời được xác định rõ ràng bằng một trong 3 ngôn ngữ mà tôi thường sử dụng.

Câu trả lời:


154

Cái này khó đấy :-)

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()

Wowww! Đó là một cái gì đó. ;-) Nhưng hãy thử tương tự trong Java, chỉ cho vui!

Nhân tiện, tôi đã kiểm tra điều đó trong một trình bao, vì vậy một số lỗi có thể vẫn còn.

Thưởng thức

BIÊN TẬP:

Vì tên hộp thư có thể thay đổi từ quốc gia này sang quốc gia khác, tôi khuyên bạn nên thực hiện m.list()và chọn một mục trong đó trước m.select("the mailbox name")để tránh lỗi này:

imaplib.error: lệnh TÌM KIẾM bất hợp pháp ở tiểu bang AUTH, chỉ được phép ở tiểu bang ĐÃ CHỌN


Cảm ơn JF Wrote rằng wuick và dơ bẩn, bạn đã cho nó giá trị :-D
e-satis

Đây là một câu trả lời tốt. Nó chết với lỗi malloc trên các tệp đính kèm lớn. Python (57780) malloc: *** mmap (size = 9658368)

Nó chết ở đâu trong kịch bản? Tôi không gặp lỗi này nhưng chúng tôi có thể tìm ra cách giải quyết.
e-thoả mãn

imaplib.py lib: (*** error: không thể phân bổ khu vực) error resp, data = m.fetch (emailid, "(RFC822)") # tìm nạp tệp thư "/Library/Frameworks/Python.framework/Versions /2.5/lib/python2.5/imaplib.py", dòng 437, trong lấy typ, dat = self._simple_command (tên, message_set, message_parts)

Nếu bạn phải chạy tính năng này trên một hệ thống hoạt động mạnh, bạn nên xử lý từng email riêng biệt hay định kỳ tất cả cùng một lúc? Cả hai giải pháp sẽ yêu cầu một hàng đợi, nhưng tôi đang tự hỏi cái nào sẽ dễ mở rộng hơn?
kari.patila

9

Tôi không phải là chuyên gia về Perl, nhưng những gì tôi biết là GMail hỗ trợ IMAP và POP3, 2 giao thức hoàn toàn tiêu chuẩn và cho phép bạn làm điều đó.

Có lẽ điều đó sẽ giúp bạn bắt đầu.


IMAP Tôi sẽ nói là đáng tin cậy hơn trong số hai cho các mục đích sao lưu.
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)

chưa được kiểm tra

  1. Đảm bảo TOS cho phép các tập lệnh như vậy nếu không tài khoản của bạn sẽ bị tạm ngưng
  2. Có thể có các tùy chọn tốt hơn: chế độ ngoại tuyến GMail, Thunderbird + ExtractExtensions, GmailFS, Gmail Drive, v.v.


7

Hãy xem qua Mail :: Webmail :: Gmail :

NHẬN ĐÍNH KÈM

Có hai cách để nhận tệp đính kèm:

1 -> Bằng cách gửi tham chiếu đến tệp đính kèm cụ thể do 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 -> Hoặc bằng cách gửi ID tệp đính kèm và ID tin nhắn

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

(Trả về một tham chiếu đến một đại lượng vô hướng giữ dữ liệu từ tệp đính kèm.)


4

Trong gmail, bạn có thể lọc "có: tệp đính kèm", sử dụng nó để xác định các thư bạn sẽ nhận được khi kiểm tra. Lưu ý rằng điều này dường như cung cấp cho cả thư có tệp đính kèm (hiển thị biểu tượng kẹp giấy), cũng như hình ảnh đính kèm nội tuyến (không hiển thị kẹp giấy).

Không có API Gmail, vì vậy IMAP hoặc POP là những lựa chọn thực sự duy nhất của bạn. Các JavaMail API có thể của một số hỗ trợ cũng như bài viết rất ngắn gọn này vào file đính kèm tải về từ IMAP sử dụng Perl . Một số câu hỏi trước đây trên SO cũng có thể hữu ích.

Ví dụ PHP này cũng có thể hữu ích. Rất tiếc, từ những gì tôi có thể thấy, không có thông tin đính kèm nào được chứa trong imap_header, vì vậy, cần tải phần nội dung xuống để có thể xem trường X-Attachment-Id. (ai đó hãy chứng minh tôi sai).


3

Nếu bất kỳ ai trong số bạn đã cập nhật lên python 3.3, tôi đã lấy tập lệnh 2.7 từ ĐÂY và cập nhật nó lên 3.3. Cũng đã khắc phục một số vấn đề với cách gmail trả lại thông tin.

# 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);

    }
}

Sự phụ thuộc Maven:

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

@jechaviz tôi đang nhận được ngoại lệ máy chủ lưu trữ không xác định luôn, vui lòng giúp đỡ
Rahul Singh

1

Vì Gmail hỗ trợ các giao thức chuẩn POP và IMAP nên bất kỳ nền tảng, công cụ, ứng dụng, thành phần hoặc API nào cung cấp phía máy khách của một trong hai giao thức sẽ hoạt động.

Tôi khuyên bạn nên thực hiện tìm kiếm trên Google cho ngôn ngữ / nền tảng yêu thích của bạn (ví dụ: "python"), cộng với "pop", cộng với "imap", có lẽ là "mã nguồn mở", có thể là "tải xuống" hoặc "đánh giá" và xem những gì bạn nhận được các tùy chọn.

Có rất nhiều ứng dụng và thành phần miễn phí, hãy chọn một vài ứng dụng có vẻ xứng đáng, kiểm tra đánh giá, sau đó tải xuống và tận hưởng.


1

Bạn nên biết thực tế là bạn cần SSL để kết nối với GMail (cho cả POP3 và IMAP - điều này tất nhiên cũng đúng với các máy chủ SMTP của họ ngoài cổng 25 nhưng đó là một câu chuyện khác).


1

Đây là nội dung tôi đã viết để tải xuống bảng sao kê ngân hàng của mình trong Groovy (ngôn ngữ động cho Nền tảng 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

Đối với Java, bạn sẽ tìm thấy G4J được sử dụng. Đó là một tập hợp các API để giao tiếp với Google Mail qua Java (ảnh chụp màn hình trên trang chủ là một ứng dụng email trình diễn được xây dựng xung quanh điều này)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.