2

Everything seems to work as long as the attachment is small.
However, as I try to attach a larger file (7MB for example), the execute() method of Send just hangs.
I tried to go over the documentation and if I understand correctly I should use a send API which actually performs upload however, I didn't figure where I should provide these parameters.
Here is the email generation method :

public MimeMessage toMimeMessage(String from, Context context) throws MessagingException {
    Properties props = new Properties();
    Session session = Session.getDefaultInstance(props, null);

    MimeMessage mimeMessage = new MimeMessage(session);

    mimeMessage.setFrom(new InternetAddress(from));
    mimeMessage.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(recipient));
    mimeMessage.setSubject(subject);

    MimeBodyPart mimeBodyText = new MimeBodyPart();
    mimeBodyText.setContent(body, "text/html");
    mimeBodyText.setHeader("Content-Type", "text/plain; charset=\"UTF-8\"");

    Multipart mp = new MimeMultipart();
    mp.addBodyPart(mimeBodyText);

    if (attachments != null && attachments.size() > 0) {
        MimeBodyPart mimeBodyAttachments = new MimeBodyPart();
        for (Uri uri : attachments) {
            String fileName = UriUtils.getFileName(uri, context);
            String mimeType = UriUtils.getMimeType(uri, context);
            Log.d(TAG, "Generating file info, uri=" + uri.getPath() + ", mimeType=" + mimeType);
            FileInputStream is = UriUtils.generateFileInfo(context, uri, mimeType);
            if (is == null) {
                throw new MessagingException("Failed to get file for uri=" + uri.getPath());
            }
            try
            {
                DataSource source = new ByteArrayDataSource(is, mimeType);
                mimeBodyAttachments.setDataHandler(new DataHandler(source));
                mimeBodyAttachments.setFileName(fileName);
                mimeBodyAttachments.setHeader("Content-Type", mimeType + "; name=\"" + fileName + "\"");
            } catch (IOException e) {
                throw new MessagingException(e.getMessage());
            }
        }
        mimeBodyAttachments.setHeader("Content-Transfer-Encoding", "base64");
        mimeBodyAttachments.setDisposition(MimeBodyPart.ATTACHMENT);
        mp.addBodyPart(mimeBodyAttachments);
    }

    mimeMessage.setContent(mp);

    return mimeMessage;
}

.

Message createMessageWithEmail(MimeMessage mimeMessage) throws MessagingException, IOException {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        mimeMessage.writeTo(bytes);
        String encodedEmail = Base64.encodeBase64URLSafeString(bytes.toByteArray());
        Message message = new Message();
        message.setRaw(encodedEmail);
        return message;
    }

Followed by :

MimeMessage mimeMessage = email.toMimeMessage(userId, context);
Message message = createMessageWithEmail(mimeMessage);
Gmail.Users.Messages messages = service.users().messages();
Gmail.Users.Messages.Send send = messages.send(userId, message);
send.execute(); // method hangs when using large attachment
SagiLow
  • 5,721
  • 9
  • 60
  • 115

1 Answers1

2

As you mentioned, I think you are hitting the upper limit of allowed message size. I don't think (someone please correct me if I'm wrong) that the Java Gmail API client has any built in support for messages that go over this size, so it is up to you to implement it.

Under the hood, the messages.send-method results in a regular http POST request:

POST https://www.googleapis.com/gmail/v1/users/{USER_ID}/messages/send
Content-Type: application/json
Authorization: Bearer {ACCESS_TOKEN}

{
  "raw": "{MESSAGE_URL_SAFE_BASE64_ENCODED}"
}

This only works up to ~5 mb total size as you discovered. If you want to use the max limit of 35 mb you need to do the following:

POST https://www.googleapis.com/upload/gmail/v1/users/{USER_ID}/messages/send?uploadType=multipart
Content-Type: message/rfc822
Authorization: Bearer {ACCESS_TOKEN}

"{MESSAGE_IN_RFC822_FORMAT}"

Notice upload in the URL, the uploadType=multipart URL parameter, message/rfc822 as Content-Type and message non-encoded in the request body. This answer might give some inspiration.

So you probably need to go around (again, someone correct me if I'm wrong) the Java client and use some other library to make a regular http request yourself.

Community
  • 1
  • 1
Tholle
  • 108,070
  • 19
  • 198
  • 189
  • 1
    I've found in the library itself an API which looks like it should support 'upload', here is its signature : `send(java.lang.String userId, com.google.api.services.gmail.model.Message content, com.google.api.client.http.AbstractInputStreamContent mediaContent)` as you can see it gets `AbstractInputStreamContent` ill give it a try, unfortunately it is not documented and it's difficult to understand its use (for single and multiple attachments) – SagiLow Feb 06 '16 at 10:00