【问题标题】:How to retrieve the email body content with Gmail API?如何使用 Gmail API 检索电子邮件正文内容?
【发布时间】:2020-02-05 12:30:41
【问题描述】:

我正在学习 Gmail API。假设我有兴趣查看哪个邮件包含字符串“foobar2000”。

这是我目前的代码:

Main.java

package manhattan.email.bot;

import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.services.gmail.model.Message;
import com.google.api.services.gmail.model.MessagePart;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.List;
import java.util.Properties;

import manhattan.email.bot.google.GmailCredentials;
import manhattan.email.bot.google.GmailService;
import manhattan.email.bot.google.GmailServiceImpl;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;

public class Main {

    static final String MY_EMAIL = "xxxxx@gmail.com";
    static final String MY_CLIENT_ID = "xxxxxapps.googleusercontent.com";    
    static final String MY_CLIENT_SECRET = "xxxxx";
    static final String MY_ACCESS_TOKEN = "xxxxx";
    static final String MY_REFRESH_TOKEN = "xxxxx";

    public static void main(String[] args) {
        try {
            GmailService gmailService = new GmailServiceImpl(GoogleNetHttpTransport.newTrustedTransport());
            gmailService.setGmailCredentials(GmailCredentials.builder()
                    .userEmail(MY_EMAIL)
                    .clientId(MY_CLIENT_ID)
                    .clientSecret(MY_CLIENT_SECRET)
                    .accessToken(MY_ACCESS_TOKEN)
                    .refreshToken(MY_REFRESH_TOKEN)
                    .build());

           List<com.google.api.services.gmail.model.Message> messageList = gmailService.listMessagesMatchingQuery(MY_EMAIL,"foobar2000");
           System.out.println("Search result: ");

           for (Message m:messageList){
               System.out.println(m.toPrettyString());
            }

        }
        catch (GeneralSecurityException gse){
            System.err.println(">>> GSE: "+gse.getMessage());
        }
        catch (IOException ioe){
            System.err.println(">>> IOE: "+ioe.getMessage());
        }
    }
}

GmailCredentials.java

package manhattan.email.bot.google;

import lombok.Builder;
import lombok.Data;

@Builder
@Data
public class GmailCredentials {
    private final String userEmail;
    private final String clientId;
    private final String clientSecret;
    private final String accessToken;
    private final String refreshToken;
}

GmailService.java

package manhattan.email.bot.google;

import com.google.api.services.gmail.model.Message;
import java.io.IOException;
import java.util.List;
import javax.mail.MessagingException;

public interface GmailService {

    void setGmailCredentials(GmailCredentials credentials);
    boolean sendMessage(String recipientAddress, String subject, String body) throws MessagingException, IOException;
    List<Message> listMessagesMatchingQuery(String userId, String query) throws IOException; 
}

GmailServiceImpl.java

package manhattan.email.bot.google;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.Base64;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.model.ListMessagesResponse;
import com.google.api.services.gmail.model.Message;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 *
 * @author OCIN
 */
public class GmailServiceImpl implements GmailService {

    private static final String APPLICATION_NAME = "mail-bot";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

    private final HttpTransport httpTransport;
    private GmailCredentials gmailCredentials;

    public GmailServiceImpl(HttpTransport transport){
        this.httpTransport = transport;
    }

    private Gmail createGmail() {
        Credential credential = authorize();
        return new Gmail.Builder(httpTransport, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }

     private Credential authorize() {
        return new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(JSON_FACTORY)
                .setClientSecrets(gmailCredentials.getClientId(), gmailCredentials.getClientSecret())
                .build()
                .setAccessToken(gmailCredentials.getAccessToken())
                .setRefreshToken(gmailCredentials.getRefreshToken());
    }

    @Override
    public void setGmailCredentials(GmailCredentials credentials) {
        this.gmailCredentials = credentials;
    }

     private MimeMessage createEmail(String to, String from, String subject, String bodyText) throws MessagingException {
        MimeMessage email = new MimeMessage(Session.getDefaultInstance(new Properties(), null));
        email.setFrom(new InternetAddress(from));
        email.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to));
        email.setSubject(subject);
        email.setText(bodyText);
        return email;
    }

    private Message createMessageWithEmail(MimeMessage emailContent) throws MessagingException, IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        emailContent.writeTo(buffer);

        return new Message().setRaw(Base64.encodeBase64URLSafeString(buffer.toByteArray()));
    }

    @Override
    public boolean sendMessage(String recipientAddress, String subject, String body) throws MessagingException, IOException {
        Message message = createMessageWithEmail(
            createEmail(recipientAddress, gmailCredentials.getUserEmail(), subject, body));

        return createGmail().users()
            .messages()
            .send(gmailCredentials.getUserEmail(), message)
            .execute()
            .getLabelIds().contains("SENT");
    }

    public List<Message> listMessagesMatchingQuery(String userId, String query) throws IOException {
        ListMessagesResponse response = createGmail().users().messages().list(userId).setQ(query).execute();
        List<Message> messages = new ArrayList<Message>();

        while (response.getMessages() != null) {
            messages.addAll(response.getMessages());
            if (response.getNextPageToken() != null) {
                String pageToken = response.getNextPageToken();
                response = createGmail().users().messages().list(userId).setQ(query).setPageToken(pageToken).execute();
            } 
            else {
                break;
            }
        }

       // for (Message message : messages) {
       //     System.out.println(message.toPrettyString());
       // }

        return messages;
    }
}

我的代码的输出是:

搜索结果: {“id”:“16d929a8524a6bbd”,“threadId”:“16d929a8524a6bbd”}

这是真的,因为只有 1 封正文中带有“foobar2000”的邮件。全文内容为:

呜呜呜 foob​​ar2000 世界你好

如何获得? 我尝试在循环中使用它:

System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(m.getPayload().getParts().get(0).getBody().getData())));

给了我一个 NullPointerException...

【问题讨论】:

  • 我了解该错误仅出现在您发布的最后一段代码中。有很多方法链接在一起,所以我强烈建议将它们分开并逐步记录它们;从m 本身开始直到newStringUtf8。这样我们都可以清楚地看到NullPointerException 的来源。另一种方法是保存消息 ID 以使用 messages.get [ developers.google.com/gmail/api/v1/reference/users/messages/get ] 方法。
  • 经过一些调试...我发现m.getPayload()返回null。所以这就是NPE的原因。嗯……
  • 有趣的是,m.getSnippet() 返回:Message snippet: Bla bla bla foobar2000 Hello world -- Clive Stevenson Android Developer M: +62 822 44 5555 E: clive.stevenson@test123.com South Jakarta, Indonesia. Bla bla bla foobar2000 Hello world -- Clive Stevenson Android Developer M: +62 822 44 5555 E: clive.stevenson@test123.com South Jakarta, Indonesia. 我要查找的内容是Bla bla bla foobar2000 Hello world。如何获得?

标签: java google-api gmail gmail-api google-api-java-client


【解决方案1】:

如果我很好地理解了你的情况,你在上一条评论中说,m.getSnippet() 给你回复了这段文字:

Message snippet: Bla bla bla foobar2000 Hello world -- Clive Stevenson Android Developer M: +62 822 44 5555 E: clive.stevenson@test123.com South Jakarta, Indonesia.

而您只想以消息正文结束:

Bla bla bla foobar2000 Hello world

如果这是您的情况,您可以使用以下函数来结束消息正文:

public String getContent(Message message) {
    StringBuilder stringBuilder = new StringBuilder();
    try {
        getPlainTextFromMessageParts(message.getPayload().getParts(), stringBuilder);
        byte[] bodyBytes = Base64.decodeBase64(stringBuilder.toString());
        String text = new String(bodyBytes, StandardCharsets.UTF_8);
        return text;
    } catch (UnsupportedEncodingException e) {
        logger.error("UnsupportedEncoding: " + e.toString());
        return message.getSnippet();
    }
}

private void getPlainTextFromMessageParts(List<MessagePart> messageParts, StringBuilder stringBuilder) {
    for (MessagePart messagePart : messageParts) {
        if (messagePart.getMimeType().equals("text/plain")) {
            stringBuilder.append(messagePart.getBody().getData());
        }

        if (messagePart.getParts() != null) {
            getPlainTextFromMessageParts(messagePart.getParts(), stringBuilder);
        }
    }
}

该代码将按照您的要求提取正文。如果您需要进一步说明或需要更多帮助,请告诉我。

感谢Gerard Verbeek 分享之前的代码。

【讨论】:

  • ty,效果很好!我是这样解码的: Base64 base64Url = new Base64(true); String bodyDecoded = StringUtils.newStringUtf8(base64Url.decodeBase64(stringBuilder.toString()));
猜你喜欢
  • 1970-01-01
  • 2017-03-07
  • 2016-04-30
  • 2020-09-27
  • 2014-08-17
  • 2011-04-05
  • 2017-11-01
  • 2017-06-27
  • 2018-11-10
相关资源
最近更新 更多