From ef8d99fae355996bf10294afca4dafd6f4c7a733 Mon Sep 17 00:00:00 2001 From: sanjuktaghosh7 Date: Fri, 14 Jan 2022 13:46:01 +0000 Subject: [PATCH 1/4] git-on-borg files of gmail-api-snippets --- gmail/snippets/.gitignore | 61 +++ gmail/snippets/build.gradle | 18 + gmail/snippets/settings.gradle | 19 + gmail/snippets/src/main/java/SendEmail.java | 183 ++++++++ .../src/main/java/SettingsSnippets.java | 106 +++++ .../snippets/src/main/java/SmimeSnippets.java | 275 ++++++++++++ gmail/snippets/src/test/java/BaseTest.java | 81 ++++ .../snippets/src/test/java/SendEmailTest.java | 70 +++ .../src/test/java/SettingsSnippetsTest.java | 77 ++++ .../src/test/java/SmimeSnippetsTest.java | 410 ++++++++++++++++++ 10 files changed, 1300 insertions(+) create mode 100644 gmail/snippets/.gitignore create mode 100644 gmail/snippets/build.gradle create mode 100644 gmail/snippets/settings.gradle create mode 100644 gmail/snippets/src/main/java/SendEmail.java create mode 100644 gmail/snippets/src/main/java/SettingsSnippets.java create mode 100644 gmail/snippets/src/main/java/SmimeSnippets.java create mode 100644 gmail/snippets/src/test/java/BaseTest.java create mode 100644 gmail/snippets/src/test/java/SendEmailTest.java create mode 100644 gmail/snippets/src/test/java/SettingsSnippetsTest.java create mode 100644 gmail/snippets/src/test/java/SmimeSnippetsTest.java diff --git a/gmail/snippets/.gitignore b/gmail/snippets/.gitignore new file mode 100644 index 00000000..060526ad --- /dev/null +++ b/gmail/snippets/.gitignore @@ -0,0 +1,61 @@ +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ + +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries +# .idea/shelf + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +.idea/gradle.xml +.idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache diff --git a/gmail/snippets/build.gradle b/gmail/snippets/build.gradle new file mode 100644 index 00000000..bd5284f5 --- /dev/null +++ b/gmail/snippets/build.gradle @@ -0,0 +1,18 @@ +apply plugin: 'java' + +repositories { + // Use 'jcenter' for resolving your dependencies. + mavenLocal() + jcenter() +} + +dependencies { + compile 'com.google.api-client:google-api-client:1.22.0' + compile 'com.google.apis:google-api-services-gmail:v1-rev62-1.22.0' + compile 'com.google.code.gson:gson:2.4' + compile 'javax.mail:mail:1.4' + compile 'org.apache.commons:commons-csv:1.1' + testCompile 'junit:junit:4.12' + testCompile 'org.hamcrest:hamcrest-all:1.3' + testCompile 'org.mockito:mockito-core:2.7.19' +} diff --git a/gmail/snippets/settings.gradle b/gmail/snippets/settings.gradle new file mode 100644 index 00000000..f93899b1 --- /dev/null +++ b/gmail/snippets/settings.gradle @@ -0,0 +1,19 @@ +/* + * This settings file was auto generated by the Gradle buildInit task + * by 'sbazyl' at '10/22/15 11:30 AM' with Gradle 2.7 + * + * The settings file is used to specify which projects to include in your build. + * In a single project build this file can be empty or even removed. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user guide at https://docs.gradle.org/2.7/userguide/multi_project_builds.html + */ + +/* +// To declare projects as part of a multi-project build use the 'include' method +include 'shared' +include 'api' +include 'services:webservice' +*/ + +rootProject.name = 'java' diff --git a/gmail/snippets/src/main/java/SendEmail.java b/gmail/snippets/src/main/java/SendEmail.java new file mode 100644 index 00000000..e8f39050 --- /dev/null +++ b/gmail/snippets/src/main/java/SendEmail.java @@ -0,0 +1,183 @@ +import com.google.api.client.repackaged.org.apache.commons.codec.binary.Base64; +import com.google.api.services.gmail.Gmail; +import com.google.api.services.gmail.model.Draft; +import com.google.api.services.gmail.model.Message; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.Properties; + +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.activation.FileDataSource; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; + +// ... + +public class SendEmail { + + // ... + + // [START create_draft] + /** + * Create draft email. + * + * @param service an authorized Gmail API instance + * @param userId user's email address. The special value "me" + * can be used to indicate the authenticated user + * @param emailContent the MimeMessage used as email within the draft + * @return the created draft + * @throws MessagingException + * @throws IOException + */ + public static Draft createDraft(Gmail service, + String userId, + MimeMessage emailContent) + throws MessagingException, IOException { + Message message = createMessageWithEmail(emailContent); + Draft draft = new Draft(); + draft.setMessage(message); + draft = service.users().drafts().create(userId, draft).execute(); + + System.out.println("Draft id: " + draft.getId()); + System.out.println(draft.toPrettyString()); + return draft; + } + // [END create_draft] + + + // [START send_email] + /** + * Send an email from the user's mailbox to its recipient. + * + * @param service Authorized Gmail API instance. + * @param userId User's email address. The special value "me" + * can be used to indicate the authenticated user. + * @param emailContent Email to be sent. + * @return The sent message + * @throws MessagingException + * @throws IOException + */ + public static Message sendMessage(Gmail service, + String userId, + MimeMessage emailContent) + throws MessagingException, IOException { + Message message = createMessageWithEmail(emailContent); + message = service.users().messages().send(userId, message).execute(); + + System.out.println("Message id: " + message.getId()); + System.out.println(message.toPrettyString()); + return message; + } + // [END send_email] + + + // [START create_message] + /** + * Create a message from an email. + * + * @param emailContent Email to be set to raw of message + * @return a message containing a base64url encoded email + * @throws IOException + * @throws MessagingException + */ + public static Message createMessageWithEmail(MimeMessage emailContent) + throws MessagingException, IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + emailContent.writeTo(buffer); + byte[] bytes = buffer.toByteArray(); + String encodedEmail = Base64.encodeBase64URLSafeString(bytes); + Message message = new Message(); + message.setRaw(encodedEmail); + return message; + } + // [END create_message] + + // [START create_email] + /** + * Create a MimeMessage using the parameters provided. + * + * @param to email address of the receiver + * @param from email address of the sender, the mailbox account + * @param subject subject of the email + * @param bodyText body text of the email + * @return the MimeMessage to be used to send email + * @throws MessagingException + */ + public static MimeMessage createEmail(String to, + String from, + String subject, + String bodyText) + throws MessagingException { + Properties props = new Properties(); + Session session = Session.getDefaultInstance(props, null); + + MimeMessage email = new MimeMessage(session); + + email.setFrom(new InternetAddress(from)); + email.addRecipient(javax.mail.Message.RecipientType.TO, + new InternetAddress(to)); + email.setSubject(subject); + email.setText(bodyText); + return email; + } + // [END create_email] + + + // [START create_email_attachment] + /** + * Create a MimeMessage using the parameters provided. + * + * @param to Email address of the receiver. + * @param from Email address of the sender, the mailbox account. + * @param subject Subject of the email. + * @param bodyText Body text of the email. + * @param file Path to the file to be attached. + * @return MimeMessage to be used to send email. + * @throws MessagingException + */ + public static MimeMessage createEmailWithAttachment(String to, + String from, + String subject, + String bodyText, + File file) + throws MessagingException, IOException { + Properties props = new Properties(); + Session session = Session.getDefaultInstance(props, null); + + MimeMessage email = new MimeMessage(session); + + email.setFrom(new InternetAddress(from)); + email.addRecipient(javax.mail.Message.RecipientType.TO, + new InternetAddress(to)); + email.setSubject(subject); + + MimeBodyPart mimeBodyPart = new MimeBodyPart(); + mimeBodyPart.setContent(bodyText, "text/plain"); + + Multipart multipart = new MimeMultipart(); + multipart.addBodyPart(mimeBodyPart); + + mimeBodyPart = new MimeBodyPart(); + DataSource source = new FileDataSource(file); + + mimeBodyPart.setDataHandler(new DataHandler(source)); + mimeBodyPart.setFileName(file.getName()); + + multipart.addBodyPart(mimeBodyPart); + email.setContent(multipart); + + return email; + } + // [END create_email_attachment] + + // ... + +} diff --git a/gmail/snippets/src/main/java/SettingsSnippets.java b/gmail/snippets/src/main/java/SettingsSnippets.java new file mode 100644 index 00000000..fab67fa6 --- /dev/null +++ b/gmail/snippets/src/main/java/SettingsSnippets.java @@ -0,0 +1,106 @@ +import com.google.api.client.googleapis.batch.BatchRequest; +import com.google.api.client.googleapis.json.GoogleJsonError; +import com.google.api.client.http.FileContent; +import com.google.api.client.http.HttpHeaders; +import com.google.api.client.util.DateTime; +import com.google.api.services.gmail.Gmail; +import com.google.api.services.gmail.model.*; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + + +public class SettingsSnippets { + + private Gmail service; + + public SettingsSnippets(Gmail service) { + this.service = service; + } + + public String updateSignature() throws IOException { + Gmail gmailService = this.service; + // [START updateSignature] + SendAs primaryAlias = null; + ListSendAsResponse aliases = gmailService.users().settings().sendAs().list("me").execute(); + for (SendAs alias: aliases.getSendAs()) { + if (alias.getIsPrimary()) { + primaryAlias = alias; + break; + } + } + SendAs aliasSettings = new SendAs().setSignature("I heart cats."); + SendAs result = gmailService.users().settings().sendAs().patch( + "me", + primaryAlias.getSendAsEmail(), + aliasSettings) + .execute(); + System.out.println("Updated signature for " + result.getDisplayName()); + // [END updateSignature] + return result.getSignature(); + } + + public String createFilter(String realLabelId) throws IOException { + Gmail gmailService = this.service; + // [START createFilter] + String labelId = "Label_14"; // ID of the user label to add + // [START_EXCLUDE silent] + labelId = realLabelId; + // [END_EXCLUDE] + Filter filter = new Filter() + .setCriteria(new FilterCriteria() + .setFrom("cat-enthusiasts@example.com")) + .setAction(new FilterAction() + .setAddLabelIds(Arrays.asList(labelId)) + .setRemoveLabelIds(Arrays.asList("INBOX"))); + Filter result = gmailService.users().settings().filters().create("me", filter).execute(); + System.out.println("Created filter " + result.getId()); + // [END createFilter] + return result.getId(); + } + + public AutoForwarding enableForwarding(String realForwardingAddress) throws IOException { + Gmail gmailService = this.service; + // [START enableForwarding] + ForwardingAddress address = new ForwardingAddress() + .setForwardingEmail("user2@example.com"); + // [START_EXCLUDE silent] + address.setForwardingEmail(realForwardingAddress); + // [END_EXCLUDE] + ForwardingAddress createAddressResult = gmailService.users().settings().forwardingAddresses() + .create("me", address).execute(); + if (createAddressResult.getVerificationStatus().equals("accepted")) { + AutoForwarding autoForwarding = new AutoForwarding() + .setEnabled(true) + .setEmailAddress(address.getForwardingEmail()) + .setDisposition("trash"); + autoForwarding = gmailService.users().settings().updateAutoForwarding("me", autoForwarding).execute(); + // [START_EXCLUDE silent] + return autoForwarding; + } + // [END enableForwarding] + return null; + } + + public VacationSettings enableAutoReply() throws IOException { + Gmail gmailService = this.service; + // [START enableAutoReply] + VacationSettings vacationSettings = new VacationSettings() + .setEnableAutoReply(true) + .setResponseBodyHtml("I'm on vacation and will reply when I'm back in the office. Thanks!") + .setRestrictToDomain(true) + .setStartTime(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) * 1000) + .setEndTime(LocalDateTime.now().plusDays(7).toEpochSecond(ZoneOffset.UTC) * 1000); + VacationSettings response = gmailService.users().settings().updateVacation("me", vacationSettings).execute(); + // [END enableAutoReply] + return response; + } + +} diff --git a/gmail/snippets/src/main/java/SmimeSnippets.java b/gmail/snippets/src/main/java/SmimeSnippets.java new file mode 100644 index 00000000..12f895ca --- /dev/null +++ b/gmail/snippets/src/main/java/SmimeSnippets.java @@ -0,0 +1,275 @@ +import com.google.api.services.gmail.Gmail; +import com.google.api.services.gmail.model.*; +import com.google.api.services.gmail.model.SmimeInfo; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Base64; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; + +class SmimeSnippets { + + SmimeSnippets() {} + + // [START create_smime_info] + /** + * Create an SmimeInfo resource for a certificate from file. + * + * @param filename Name of the file containing the S/MIME certificate. + * @param password Password for the certificate file, or null if the file is not + * password-protected. + * @return An SmimeInfo object with the specified certificate. + */ + public static SmimeInfo createSmimeInfo(String filename, String password) { + SmimeInfo smimeInfo = null; + InputStream in = null; + + try { + File file = new File(filename); + in = new FileInputStream(file); + byte fileContent[] = new byte[(int) file.length()]; + in.read(fileContent); + + smimeInfo = new SmimeInfo(); + smimeInfo.setPkcs12(Base64.getUrlEncoder().encodeToString(fileContent)); + if (password != null && password.length() > 0) { + smimeInfo.setEncryptedKeyPassword(password); + } + } catch (Exception e) { + System.out.printf("An error occured while reading the certificate file: %s\n", e); + } finally { + try { + if (in != null) { + in.close(); + } + } catch (IOException ioe) { + System.out.printf("An error occured while closing the input stream: %s\n", ioe); + } + } + + return smimeInfo; + } + // [END create_smime_info] + + // [START insert_smime_info] + /** + * Upload an S/MIME certificate for the user. + * + * @param service Authorized GMail API service instance. + * @param userId User's email address. + * @param sendAsEmail The "send as" email address, or null if it should be the same as userId. + * @param smimeInfo The SmimeInfo object containing the user's S/MIME certificate. + * @return An SmimeInfo object with details about the uploaded certificate. + */ + public static SmimeInfo insertSmimeInfo( + Gmail service, String userId, String sendAsEmail, SmimeInfo smimeInfo) { + if (sendAsEmail == null) { + sendAsEmail = userId; + } + + try { + SmimeInfo results = + service + .users() + .settings() + .sendAs() + .smimeInfo() + .insert(userId, sendAsEmail, smimeInfo) + .execute(); + System.out.printf("Inserted certificate, id: %s\n", results.getId()); + return results; + } catch (IOException e) { + System.err.printf("An error occured: %s", e); + } + + return null; + } + // [END insert_smime_info] + + // [START insert_cert_from_csv] + /** + * A builder that returns a GMail API service instance that is authorized to act on behalf of the + * specified user. + */ + @FunctionalInterface + public interface GmailServiceBuilder { + Gmail buildGmailServiceFromUserId(String userId) throws IOException; + } + + /** + * Upload S/MIME certificates based on the contents of a CSV file. + * + *

Each row of the CSV file should contain a user ID, path to the certificate, and the + * certificate password. + * + * @param serviceBuilder A function that returns an authorized GMail API service instance for a + * given user. + * @param csvFilename Name of the CSV file. + */ + public static void insertCertFromCsv(GmailServiceBuilder serviceBuilder, String csvFilename) { + try { + File csvFile = new File(csvFilename); + CSVParser parser = + CSVParser.parse(csvFile, java.nio.charset.StandardCharsets.UTF_8, CSVFormat.DEFAULT); + for (CSVRecord record : parser) { + String userId = record.get(0); + String certFilename = record.get(1); + String certPassword = record.get(2); + SmimeInfo smimeInfo = createSmimeInfo(certFilename, certPassword); + if (smimeInfo != null) { + insertSmimeInfo( + serviceBuilder.buildGmailServiceFromUserId(userId), userId, userId, smimeInfo); + } else { + System.err.printf("Unable to read certificate file for userId: %s\n", userId); + } + } + } catch (Exception e) { + System.err.printf("An error occured while reading the CSV file: %s", e); + } + } + // [END insert_cert_from_csv] + + // [START update_smime_certs] + /** + * Update S/MIME certificates for the user. + * + *

First performs a lookup of all certificates for a user. If there are no certificates, or + * they all expire before the specified date/time, uploads the certificate in the specified file. + * If the default certificate is expired or there was no default set, chooses the certificate with + * the expiration furthest into the future and sets it as default. + * + * @param service Authorized GMail API service instance. + * @param userId User's email address. + * @param sendAsEmail The "send as" email address, or None if it should be the same as user_id. + * @param certFilename Name of the file containing the S/MIME certificate. + * @param certPassword Password for the certificate file, or None if the file is not + * password-protected. + * @param expireTime DateTime object against which the certificate expiration is compared. If + * None, uses the current time. @ returns: The ID of the default certificate. + * @return The ID of the default certifcate. + */ + public static String updateSmimeCerts( + Gmail service, + String userId, + String sendAsEmail, + String certFilename, + String certPassword, + LocalDateTime expireTime) { + if (sendAsEmail == null) { + sendAsEmail = userId; + } + + ListSmimeInfoResponse listResults = null; + try { + listResults = + service.users().settings().sendAs().smimeInfo().list(userId, sendAsEmail).execute(); + } catch (IOException e) { + System.err.printf("An error occurred during list: %s\n", e); + return null; + } + + String defaultCertId = null; + String bestCertId = null; + LocalDateTime bestCertExpire = LocalDateTime.MIN; + + if (expireTime == null) { + expireTime = LocalDateTime.now(); + } + if (listResults != null && listResults.getSmimeInfo() != null) { + for (SmimeInfo smimeInfo : listResults.getSmimeInfo()) { + String certId = smimeInfo.getId(); + boolean isDefaultCert = smimeInfo.getIsDefault(); + if (isDefaultCert) { + defaultCertId = certId; + } + LocalDateTime exp = + LocalDateTime.ofInstant( + Instant.ofEpochMilli(smimeInfo.getExpiration()), ZoneId.systemDefault()); + if (exp.isAfter(expireTime)) { + if (exp.isAfter(bestCertExpire)) { + bestCertId = certId; + bestCertExpire = exp; + } + } else { + if (isDefaultCert) { + defaultCertId = null; + } + } + } + } + if (defaultCertId == null) { + String defaultId = bestCertId; + if (defaultId == null && certFilename != null) { + SmimeInfo smimeInfo = createSmimeInfo(certFilename, certPassword); + SmimeInfo insertResults = insertSmimeInfo(service, userId, sendAsEmail, smimeInfo); + if (insertResults != null) { + defaultId = insertResults.getId(); + } + } + + if (defaultId != null) { + try { + service + .users() + .settings() + .sendAs() + .smimeInfo() + .setDefault(userId, sendAsEmail, defaultId) + .execute(); + return defaultId; + } catch (IOException e) { + System.err.printf("An error occured during setDefault: %s", e); + } + } + } else { + return defaultCertId; + } + + return null; + } + + /** + * Update S/MIME certificates based on the contents of a CSV file. + * + *

Each row of the CSV file should contain a user ID, path to the certificate, and the + * certificate password. + * + * @param serviceBuilder A function that returns an authorized GMail API service instance for a + * given user. + * @param csvFilename Name of the CSV file. + * @param expireTime DateTime object against which the certificate expiration is compared. If + * None, uses the current time. + */ + public static void updateSmimeFromCsv( + GmailServiceBuilder serviceBuilder, String csvFilename, LocalDateTime expireTime) { + try { + File csvFile = new File(csvFilename); + CSVParser parser = + CSVParser.parse( + csvFile, + java.nio.charset.StandardCharsets.UTF_8, + CSVFormat.DEFAULT.withHeader().withSkipHeaderRecord()); + for (CSVRecord record : parser) { + String userId = record.get(0); + String certFilename = record.get(1); + String certPassword = record.get(2); + updateSmimeCerts( + serviceBuilder.buildGmailServiceFromUserId(userId), + userId, + userId, + certFilename, + certPassword, + expireTime); + } + } catch (Exception e) { + System.err.printf("An error occured while reading the CSV file: %s", e); + } + } + // [END update_smime_certs] +} diff --git a/gmail/snippets/src/test/java/BaseTest.java b/gmail/snippets/src/test/java/BaseTest.java new file mode 100644 index 00000000..9fa3740f --- /dev/null +++ b/gmail/snippets/src/test/java/BaseTest.java @@ -0,0 +1,81 @@ +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.gmail.Gmail; +import com.google.api.services.gmail.GmailScopes; +import org.junit.Before; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.*; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +public class BaseTest { + + public static final String TEST_USER = "gdtest1@appsrocks.com"; + public static final String RECIPIENT = "gdtest2@appsrocks.com"; + public static final String FORWARDING_ADDRESS = "gdtest2@appsrocks.com"; + + static { + enableLogging(); + } + + protected Gmail service; + + + public static void enableLogging() { + Logger logger = Logger.getLogger(HttpTransport.class.getName()); + logger.setLevel(Level.ALL); + logger.addHandler(new Handler() { + + @Override + public void close() throws SecurityException { + } + + @Override + public void flush() { + } + + @Override + public void publish(LogRecord record) { + // default ConsoleHandler will print >= INFO to System.err + if (record.getLevel().intValue() < Level.INFO.intValue()) { + System.out.println(record.getMessage()); + } + } + }); + } + + public GoogleCredential getCredential() throws IOException { + GoogleCredential defaultCredentials = GoogleCredential.getApplicationDefault(); + return new GoogleCredential.Builder() + .setServiceAccountId(defaultCredentials.getServiceAccountId()) + .setServiceAccountPrivateKey(defaultCredentials.getServiceAccountPrivateKey()) + .setServiceAccountPrivateKeyId(defaultCredentials.getServiceAccountPrivateKeyId()) + .setServiceAccountUser(TEST_USER) + .setJsonFactory(defaultCredentials.getJsonFactory()) + .setTransport(defaultCredentials.getTransport()) + .setServiceAccountScopes(Arrays.asList(GmailScopes.GMAIL_COMPOSE, GmailScopes.GMAIL_SEND, GmailScopes.GMAIL_LABELS, GmailScopes.GMAIL_SETTINGS_BASIC, GmailScopes.GMAIL_SETTINGS_SHARING)) + .build(); + } + + public Gmail buildService() throws IOException, GeneralSecurityException { + GoogleCredential credential = getCredential(); + return new Gmail.Builder( + new NetHttpTransport(), + JacksonFactory.getDefaultInstance(), + credential) + .setApplicationName("Drive API Snippets") + .build(); + } + + @Before + public void setup() throws IOException, GeneralSecurityException { + this.service = buildService(); + } + +} diff --git a/gmail/snippets/src/test/java/SendEmailTest.java b/gmail/snippets/src/test/java/SendEmailTest.java new file mode 100644 index 00000000..6d17129b --- /dev/null +++ b/gmail/snippets/src/test/java/SendEmailTest.java @@ -0,0 +1,70 @@ +import com.google.api.services.gmail.model.*; +import org.junit.Test; + +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class SendEmailTest extends BaseTest { + + @Test + public void createEmail() throws MessagingException, IOException { + MimeMessage mimeMessage = SendEmail.createEmail(RECIPIENT, + TEST_USER, + "test", + "Hello!"); + assertEquals("test", mimeMessage.getSubject()); + assertEquals("Hello!", mimeMessage.getContent()); + assertEquals(RECIPIENT, mimeMessage.getRecipients(Message.RecipientType.TO)[0].toString()); + assertEquals(TEST_USER, mimeMessage.getFrom()[0].toString()); + } + + @Test + public void createEmailWithAttachment() throws MessagingException, IOException { + MimeMessage mimeMessage = SendEmail.createEmailWithAttachment(RECIPIENT, + TEST_USER, + "test", + "Hello!", + new java.io.File("files/photo.jpg")); + assertEquals("test", mimeMessage.getSubject()); + assertEquals(RECIPIENT, mimeMessage.getRecipients(Message.RecipientType.TO)[0].toString()); + assertEquals(TEST_USER, mimeMessage.getFrom()[0].toString()); + } + + @Test + public void createMessageWithEmail() throws MessagingException, IOException { + MimeMessage mimeMessage = SendEmail.createEmail(RECIPIENT, + TEST_USER, + "test", + "Hello!"); + + com.google.api.services.gmail.model.Message message = SendEmail.createMessageWithEmail(mimeMessage); + assertNotNull(message.getRaw()); // Weak assertion... + } + + @Test + public void createDraft() throws MessagingException, IOException { + MimeMessage mimeMessage = SendEmail.createEmail(RECIPIENT, + TEST_USER, + "test", + "Hello!"); + Draft draft = SendEmail.createDraft(this.service, "me", mimeMessage); + assertNotNull(draft); + this.service.users().drafts().delete("me", draft.getId()); + } + + @Test + public void sendEmail() throws MessagingException, IOException { + MimeMessage mimeMessage = SendEmail.createEmailWithAttachment(RECIPIENT, + TEST_USER, + "test", + "Hello!", + new java.io.File("files/photo.jpg")); + com.google.api.services.gmail.model.Message message = SendEmail.sendMessage(this.service, "me", mimeMessage); + assertNotNull(message); + } +} diff --git a/gmail/snippets/src/test/java/SettingsSnippetsTest.java b/gmail/snippets/src/test/java/SettingsSnippetsTest.java new file mode 100644 index 00000000..8622e8d4 --- /dev/null +++ b/gmail/snippets/src/test/java/SettingsSnippetsTest.java @@ -0,0 +1,77 @@ + +import com.google.api.services.gmail.model.AutoForwarding; +import com.google.api.services.gmail.model.Label; +import com.google.api.services.gmail.model.ListLabelsResponse; +import com.google.api.services.gmail.model.VacationSettings; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import static org.junit.Assert.*; + +public class SettingsSnippetsTest extends BaseTest { + + private SettingsSnippets snippets; + private Label testLabel = null; + + @Before + public void createSnippets() { + this.snippets = new SettingsSnippets(this.service); + } + + @Before + public void createLabel() throws IOException { + ListLabelsResponse response = this.service.users().labels().list("me").execute(); + for (Label l : response.getLabels()) { + if (l.getName().equals("testLabel")) { + testLabel = l; + } + } + if (testLabel == null) { + Label label = new Label() + .setName("testLabel") + .setLabelListVisibility("labelShow") + .setMessageListVisibility("show"); + testLabel = this.service.users().labels().create("me", label).execute(); + } + } + + @After + public void deleteLabel() throws IOException { + if (testLabel != null) { + this.service.users().labels().delete("me", testLabel.getId()).execute(); + testLabel = null; + } + } + + @Test + public void updateSignature() throws IOException, GeneralSecurityException { + String signature = this.snippets.updateSignature(); + assertEquals("I heart cats.", signature); + } + + @Test + public void createFilter() throws IOException, GeneralSecurityException { + String id = this.snippets.createFilter(testLabel.getId()); + assertNotNull(id); + this.service.users().settings().filters().delete("me", id).execute(); + } + + @Test + public void enableAutoForwarding() throws IOException, GeneralSecurityException { + AutoForwarding forwarding = this.snippets.enableForwarding(FORWARDING_ADDRESS); + assertNotNull(forwarding); + forwarding = new AutoForwarding().setEnabled(false); + this.service.users().settings().updateAutoForwarding("me", forwarding).execute(); + this.service.users().settings().forwardingAddresses().delete("me", FORWARDING_ADDRESS).execute(); + } + + @Test + public void enableAutoReply() throws IOException, GeneralSecurityException { + VacationSettings settings = this.snippets.enableAutoReply(); + assertNotNull(settings); + } +} diff --git a/gmail/snippets/src/test/java/SmimeSnippetsTest.java b/gmail/snippets/src/test/java/SmimeSnippetsTest.java new file mode 100644 index 00000000..6aefb3e3 --- /dev/null +++ b/gmail/snippets/src/test/java/SmimeSnippetsTest.java @@ -0,0 +1,410 @@ +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import com.google.api.services.gmail.Gmail; +import com.google.api.services.gmail.model.*; +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class SmimeSnippetsTest { + + private static final long CURRENT_TIME_MS = 1234567890; + private static final LocalDateTime CURRENT_TIME = + LocalDateTime.ofInstant(Instant.ofEpochMilli(CURRENT_TIME_MS), ZoneId.systemDefault()); + private static final String TEST_USER = "user1@example.com"; + + @Mock private Gmail mockService; + @Mock private Gmail.Users mockUsers; + @Mock private Gmail.Users.Settings mockSettings; + @Mock private Gmail.Users.Settings.SendAs mockSendAs; + @Mock private Gmail.Users.Settings.SendAs.SmimeInfo mockSmimeInfo; + @Mock private Gmail.Users.Settings.SendAs.SmimeInfo.Delete mockDelete; + @Mock private Gmail.Users.Settings.SendAs.SmimeInfo.Get mockGet; + @Mock private Gmail.Users.Settings.SendAs.SmimeInfo.Insert mockInsert; + @Mock private Gmail.Users.Settings.SendAs.SmimeInfo.List mockList; + @Mock private Gmail.Users.Settings.SendAs.SmimeInfo.SetDefault mockSetDefault; + + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Before + public void setup() throws IOException { + when(mockService.users()).thenReturn(mockUsers); + when(mockUsers.settings()).thenReturn(mockSettings); + when(mockSettings.sendAs()).thenReturn(mockSendAs); + when(mockSendAs.smimeInfo()).thenReturn(mockSmimeInfo); + + when(mockSmimeInfo.delete(any(), any(), any())).thenReturn(mockDelete); + when(mockSmimeInfo.get(any(), any(), any())).thenReturn(mockGet); + when(mockSmimeInfo.insert(any(), any(), any())).thenReturn(mockInsert); + when(mockSmimeInfo.list(any(), any())).thenReturn(mockList); + when(mockSmimeInfo.setDefault(any(), any(), any())).thenReturn(mockSetDefault); + } + + @After + public void tearDown() throws IOException { + verifyNoMoreInteractions(mockService); + verifyNoMoreInteractions(mockUsers); + verifyNoMoreInteractions(mockSettings); + verifyNoMoreInteractions(mockSendAs); + verifyNoMoreInteractions(mockSmimeInfo); + verifyNoMoreInteractions(mockInsert); + verifyNoMoreInteractions(mockList); + verifyNoMoreInteractions(mockSetDefault); + + verifyZeroInteractions(mockDelete); + verifyZeroInteractions(mockGet); + } + + @Test + public void testCreateSmimeInfo() { + SmimeInfo smimeInfo = SmimeSnippets.createSmimeInfo("files/cert.p12", null /* password */); + + assertNotNull(smimeInfo); + assertNull(smimeInfo.getEncryptedKeyPassword()); + assertNull(smimeInfo.getExpiration()); + assertNull(smimeInfo.getId()); + assertNull(smimeInfo.getIsDefault()); + assertNull(smimeInfo.getIssuerCn()); + assertNull(smimeInfo.getPem()); + assertThat(smimeInfo.getPkcs12().length(), greaterThan(0)); + } + + @Test + public void testCreateSmimeInfoWithPassword() { + SmimeInfo smimeInfo = SmimeSnippets.createSmimeInfo("files/cert.p12", "certpass"); + + assertNotNull(smimeInfo); + assertEquals(smimeInfo.getEncryptedKeyPassword(), "certpass"); + assertNull(smimeInfo.getExpiration()); + assertNull(smimeInfo.getId()); + assertNull(smimeInfo.getIsDefault()); + assertNull(smimeInfo.getIssuerCn()); + assertNull(smimeInfo.getPem()); + assertThat(smimeInfo.getPkcs12().length(), greaterThan(0)); + } + + @Test + public void testCreateSmimeInfoFileNotFound() { + SmimeInfo smimeInfo = SmimeSnippets.createSmimeInfo("files/notfound.p12", null /* password */); + + assertNull(smimeInfo); + } + + @Test + public void testInsertSmimeInfo() throws IOException { + SmimeInfo insertResult = makeFakeInsertResult(); + when(mockInsert.execute()).thenReturn(insertResult); + + SmimeInfo smimeInfo = SmimeSnippets.createSmimeInfo("files/cert.p12", null /* password */); + SmimeInfo result = SmimeSnippets.insertSmimeInfo(mockService, TEST_USER, TEST_USER, smimeInfo); + + verifySmimeApiCalled(1); + verify(mockSmimeInfo).insert(eq(TEST_USER), eq(TEST_USER), eq(smimeInfo)); + verify(mockInsert).execute(); + + assertEquals(insertResult, result); + } + + @Test + public void testInsertSmimeInfoError() throws IOException { + when(mockInsert.execute()).thenThrow(IOException.class); + + SmimeInfo smimeInfo = SmimeSnippets.createSmimeInfo("files/cert.p12", null /* password */); + SmimeInfo result = SmimeSnippets.insertSmimeInfo(mockService, TEST_USER, TEST_USER, smimeInfo); + + verifySmimeApiCalled(1); + verify(mockSmimeInfo).insert(eq(TEST_USER), eq(TEST_USER), eq(smimeInfo)); + verify(mockInsert).execute(); + + assertNull(result); + } + + @Test + public void testInsertSmimeFromCsv() throws IOException { + when(mockInsert.execute()).thenReturn(makeFakeInsertResult()); + + SmimeSnippets.insertCertFromCsv((u) -> mockService, "files/certs.csv"); + + verifySmimeApiCalled(2); + verify(mockSmimeInfo).insert(eq("user1@example.com"), eq("user1@example.com"), any()); + verify(mockSmimeInfo).insert(eq("user2@example.com"), eq("user2@example.com"), any()); + verify(mockInsert, times(2)).execute(); + } + + @Test + public void testInsertSmimeFromCsvFails() throws IOException { + when(mockInsert.execute()).thenReturn(makeFakeInsertResult()); + + SmimeSnippets.insertCertFromCsv((u) -> mockService, "files/notfound.csv"); + } + + @Test + public void testUpdateSmimeCertsNoCerts() throws IOException { + when(mockList.execute()).thenReturn(makeFakeListResult()); + + String defaultCertId = + SmimeSnippets.updateSmimeCerts( + mockService, + TEST_USER, + TEST_USER, + null /* certFilename */, + null /* certPassword */, + CURRENT_TIME); + + verifySmimeApiCalled(1); + verify(mockSmimeInfo).list(eq(TEST_USER), eq(TEST_USER)); + verify(mockList).execute(); + + assertNull(defaultCertId); + } + + @Test + public void testUpdateSmimeCertsNoCertsUploadNewCert() throws IOException { + when(mockList.execute()).thenReturn(makeFakeListResult()); + when(mockInsert.execute()).thenReturn(makeFakeInsertResult()); + + String defaultCertId = + SmimeSnippets.updateSmimeCerts( + mockService, + TEST_USER, + TEST_USER, + "files/cert.p12", + null /* certPassword */, + CURRENT_TIME); + + verifySmimeApiCalled(3); + verify(mockSmimeInfo).list(eq(TEST_USER), eq(TEST_USER)); + verify(mockSmimeInfo).insert(eq(TEST_USER), eq(TEST_USER), any()); + verify(mockSmimeInfo).setDefault(eq(TEST_USER), eq(TEST_USER), eq("new_certificate_id")); + verify(mockList).execute(); + verify(mockInsert).execute(); + verify(mockSetDefault).execute(); + + assertEquals(defaultCertId, "new_certificate_id"); + } + + @Test + public void testUpdateSmimeCertsValidDefaultCertNoUpload() throws IOException { + ListSmimeInfoResponse listResponse = + makeFakeListResult(Arrays.asList(true), Arrays.asList(CURRENT_TIME_MS + 1)); + when(mockList.execute()).thenReturn(listResponse); + + String defaultCertId = + SmimeSnippets.updateSmimeCerts( + mockService, + TEST_USER, + TEST_USER, + "files/cert.p12", + null /* certPassword */, + CURRENT_TIME); + + verifySmimeApiCalled(1); + verify(mockSmimeInfo).list(eq(TEST_USER), eq(TEST_USER)); + verify(mockList).execute(); + + assertEquals(defaultCertId, "existing_certificate_id0"); + } + + @Test + public void testUpdateSmimeCertsExpiredDefaultCertUploadNewCert() throws IOException { + LocalDateTime expireTime = + LocalDateTime.ofInstant(Instant.ofEpochMilli(CURRENT_TIME_MS + 2), ZoneId.systemDefault()); + ListSmimeInfoResponse listResponse = + makeFakeListResult(Arrays.asList(true), Arrays.asList(CURRENT_TIME_MS + 1)); + when(mockList.execute()).thenReturn(listResponse); + + when(mockInsert.execute()).thenReturn(makeFakeInsertResult()); + + String defaultCertId = + SmimeSnippets.updateSmimeCerts( + mockService, + TEST_USER, + TEST_USER, + "files/cert.p12", + null /* certPassword */, + expireTime); + + verifySmimeApiCalled(3); + verify(mockSmimeInfo).list(eq(TEST_USER), eq(TEST_USER)); + verify(mockSmimeInfo).insert(eq(TEST_USER), eq(TEST_USER), any()); + verify(mockSmimeInfo).setDefault(eq(TEST_USER), eq(TEST_USER), eq("new_certificate_id")); + verify(mockList).execute(); + verify(mockInsert).execute(); + verify(mockSetDefault).execute(); + + assertEquals(defaultCertId, "new_certificate_id"); + } + + @Test + public void testUpdateSmimeCertsExpiredDefaultCertOtherCertNewDefault() throws IOException { + ListSmimeInfoResponse listResponse = + makeFakeListResult( + Arrays.asList(true, false), Arrays.asList(CURRENT_TIME_MS - 1, CURRENT_TIME_MS + 1)); + when(mockList.execute()).thenReturn(listResponse); + + String defaultCertId = + SmimeSnippets.updateSmimeCerts( + mockService, + TEST_USER, + TEST_USER, + "files/cert.p12", + null /* certPassword */, + CURRENT_TIME); + + verifySmimeApiCalled(2); + verify(mockSmimeInfo).list(eq(TEST_USER), eq(TEST_USER)); + verify(mockSmimeInfo).setDefault(eq(TEST_USER), eq(TEST_USER), eq("existing_certificate_id1")); + verify(mockList).execute(); + verify(mockSetDefault).execute(); + + assertEquals(defaultCertId, "existing_certificate_id1"); + } + + @Test + public void testUpdateSmimeCertsNoCertsNoDefaultsChooseBestCertAsNewDefault() throws IOException { + ListSmimeInfoResponse listResponse = + makeFakeListResult( + Arrays.asList(false, false, false, false), + Arrays.asList( + CURRENT_TIME_MS + 2, + CURRENT_TIME_MS + 1, + CURRENT_TIME_MS + 4, + CURRENT_TIME_MS + 3)); + when(mockList.execute()).thenReturn(listResponse); + + String defaultCertId = + SmimeSnippets.updateSmimeCerts( + mockService, + TEST_USER, + TEST_USER, + "files/cert.p12", + null /* certPassword */, + CURRENT_TIME); + + verifySmimeApiCalled(2); + verify(mockSmimeInfo).list(eq(TEST_USER), eq(TEST_USER)); + verify(mockSmimeInfo).setDefault(eq(TEST_USER), eq(TEST_USER), eq("existing_certificate_id2")); + verify(mockList).execute(); + verify(mockSetDefault).execute(); + + assertEquals(defaultCertId, "existing_certificate_id2"); + } + + @Test + public void testUpdateSmimeCertsError() throws IOException { + when(mockList.execute()).thenThrow(IOException.class); + + String defaultCertId = + SmimeSnippets.updateSmimeCerts( + mockService, + TEST_USER, + TEST_USER, + "files/cert.p12", + null /* certPassword */, + CURRENT_TIME); + + verifySmimeApiCalled(1); + verify(mockSmimeInfo).list(eq(TEST_USER), eq(TEST_USER)); + verify(mockList).execute(); + + assertNull(defaultCertId); + } + + @Test + public void testUpdateSmimeFromCsv() throws IOException { + when(mockList.execute()).thenReturn(makeFakeListResult()); + when(mockInsert.execute()).thenReturn(makeFakeInsertResult()); + + SmimeSnippets.updateSmimeFromCsv((u) -> mockService, "files/certs.csv", CURRENT_TIME); + + verifySmimeApiCalled(9); + verify(mockSmimeInfo).list(eq("user1@example.com"), eq("user1@example.com")); + verify(mockSmimeInfo).list(eq("user2@example.com"), eq("user2@example.com")); + verify(mockSmimeInfo).list(eq("user3@example.com"), eq("user3@example.com")); + verify(mockSmimeInfo).insert(eq("user1@example.com"), eq("user1@example.com"), any()); + verify(mockSmimeInfo).insert(eq("user2@example.com"), eq("user2@example.com"), any()); + verify(mockSmimeInfo).insert(eq("user3@example.com"), eq("user3@example.com"), any()); + verify(mockSmimeInfo) + .setDefault(eq("user1@example.com"), eq("user1@example.com"), eq("new_certificate_id")); + verify(mockSmimeInfo) + .setDefault(eq("user2@example.com"), eq("user2@example.com"), eq("new_certificate_id")); + verify(mockSmimeInfo) + .setDefault(eq("user3@example.com"), eq("user3@example.com"), eq("new_certificate_id")); + verify(mockList, times(3)).execute(); + verify(mockInsert, times(3)).execute(); + verify(mockSetDefault, times(3)).execute(); + } + + @Test + public void testUpdateSmimeFromCsvFails() { + SmimeSnippets.insertCertFromCsv((u) -> mockService, "files/notfound.csv"); + // tearDown() verifies that there were no interactions with the API. + } + + private void verifySmimeApiCalled(int numCalls) { + verify(mockService, times(numCalls)).users(); + verify(mockUsers, times(numCalls)).settings(); + verify(mockSettings, times(numCalls)).sendAs(); + verify(mockSendAs, times(numCalls)).smimeInfo(); + } + + private ListSmimeInfoResponse makeFakeListResult(List isDefault, List expiration) { + ListSmimeInfoResponse listResponse = new ListSmimeInfoResponse(); + if (isDefault == null || expiration == null) { + return listResponse; + } + + assertEquals(isDefault.size(), expiration.size()); + + List smimeInfoList = new ArrayList(); + for (int i = 0; i < isDefault.size(); i++) { + SmimeInfo smimeInfo = new SmimeInfo(); + smimeInfo.setId(String.format("existing_certificate_id%d", i)); + smimeInfo.setIsDefault(isDefault.get(i)); + smimeInfo.setExpiration(expiration.get(i)); + smimeInfoList.add(smimeInfo); + } + listResponse.setSmimeInfo(smimeInfoList); + + return listResponse; + } + + private ListSmimeInfoResponse makeFakeListResult() { + return makeFakeListResult(null /* isDefault */, null /* expiration */); + } + + private SmimeInfo makeFakeInsertResult(String id, boolean isDefault, long expiration) { + SmimeInfo insertResult = new SmimeInfo(); + insertResult.setId(id); + insertResult.setIsDefault(isDefault); + insertResult.setExpiration(expiration); + + return insertResult; + } + + private SmimeInfo makeFakeInsertResult() { + return makeFakeInsertResult("new_certificate_id", false, CURRENT_TIME_MS + 1); + } +} From cc07ac471b29b3b671819ff7514c3de9069b42bb Mon Sep 17 00:00:00 2001 From: Manvendra-P-Singh Date: Wed, 19 Jan 2022 10:18:20 +0530 Subject: [PATCH 2/4] Update build.gradle test12 --- docs/quickstart/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quickstart/build.gradle b/docs/quickstart/build.gradle index 48c9c11a..ccbf7b75 100644 --- a/docs/quickstart/build.gradle +++ b/docs/quickstart/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'application' mainClassName = 'DocsQuickstart' sourceCompatibility = 11 -targetCompatibility = 11 +targetCompatibility = 8 version = '1.0' repositories { From 352491b4e8c189197db876886f1eec6c8fb6af36 Mon Sep 17 00:00:00 2001 From: Rajesh Mudaliyar Date: Tue, 18 Jan 2022 20:57:58 -0800 Subject: [PATCH 3/4] Update build.gradle --- docs/quickstart/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quickstart/build.gradle b/docs/quickstart/build.gradle index ccbf7b75..48c9c11a 100644 --- a/docs/quickstart/build.gradle +++ b/docs/quickstart/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'application' mainClassName = 'DocsQuickstart' sourceCompatibility = 11 -targetCompatibility = 8 +targetCompatibility = 11 version = '1.0' repositories { From 81069570fd24d68bbd9e0244b113cb0bf55e960c Mon Sep 17 00:00:00 2001 From: sanjuktaghosh7 Date: Thu, 3 Feb 2022 13:55:26 +0530 Subject: [PATCH 4/4] Create Draft with attachment gmail snippet --- .../main/java/CreateDraftWithAttachment.java | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 gmail/snippets/src/main/java/CreateDraftWithAttachment.java diff --git a/gmail/snippets/src/main/java/CreateDraftWithAttachment.java b/gmail/snippets/src/main/java/CreateDraftWithAttachment.java new file mode 100644 index 00000000..bf2d8247 --- /dev/null +++ b/gmail/snippets/src/main/java/CreateDraftWithAttachment.java @@ -0,0 +1,122 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +// [START gmail_create_draft_with_attachment] +import com.google.api.client.googleapis.json.GoogleJsonResponseException; +import com.google.api.client.http.HttpRequestInitializer; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.gson.GsonFactory; +import com.google.api.services.gmail.Gmail; +import com.google.api.services.gmail.GmailScopes; +import com.google.api.services.gmail.model.Draft; +import com.google.api.services.gmail.model.Message; +import com.google.auth.http.HttpCredentialsAdapter; +import com.google.auth.oauth2.GoogleCredentials; +import org.apache.commons.codec.binary.Base64; + +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.activation.FileDataSource; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.Properties; + +/* Class to demonstrate the use of Gmail Create Draft with attachment API */ +public class CreateDraftWithAttachment { + /** + * Create a draft email. + * + * @param fromEmailAddress - Email address to appear in the from: header. + * @param toEmailAddress - Email address of the recipient. + * @param file - Path to the file to be attached. + * @return the created draft + * @throws MessagingException - if a wrongly formatted address is encountered. + * @throws IOException - if service account credentials file not found. + */ + public static Draft createDraftMessageWithAttachment(String fromEmailAddress, + String toEmailAddress, + File file) + throws MessagingException, IOException { + // Load pre-authorized user credentials from the environment. + // TODO(developer) - See https://developers.google.com/identity for + // guides on implementing OAuth2 for your application. + GoogleCredentials credentials = GoogleCredentials.getApplicationDefault().createScoped(Collections.singletonList(GmailScopes.GMAIL_COMPOSE)); + HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter( + credentials); + + // Create the gmail API client + Gmail service = new Gmail.Builder(new NetHttpTransport(), + GsonFactory.getDefaultInstance(), + requestInitializer) + .setApplicationName("Gmail samples") + .build(); + + // Create the email content + String messageSubject = "Test message"; + String bodyText = "lorem ipsum."; + + // Encode as MIME message + Properties props = new Properties(); + Session session = Session.getDefaultInstance(props, null); + MimeMessage email = new MimeMessage(session); + email.setFrom(new InternetAddress(fromEmailAddress)); + email.addRecipient(javax.mail.Message.RecipientType.TO, + new InternetAddress(toEmailAddress)); + email.setSubject(messageSubject); + + MimeBodyPart mimeBodyPart = new MimeBodyPart(); + mimeBodyPart.setContent(bodyText, "text/plain"); + Multipart multipart = new MimeMultipart(); + multipart.addBodyPart(mimeBodyPart); + mimeBodyPart = new MimeBodyPart(); + DataSource source = new FileDataSource(file); + mimeBodyPart.setDataHandler(new DataHandler(source)); + mimeBodyPart.setFileName(file.getName()); + multipart.addBodyPart(mimeBodyPart); + email.setContent(multipart); + + // Encode and wrap the MIME message into a gmail message + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + email.writeTo(buffer); + byte[] rawMessageBytes = buffer.toByteArray(); + String encodedEmail = Base64.encodeBase64URLSafeString(rawMessageBytes); + Message message = new Message(); + message.setRaw(encodedEmail); + + try { + // Create the draft message + Draft draft = new Draft(); + draft.setMessage(message); + draft = service.users().drafts().create("me", draft).execute(); + System.out.println("Draft id: " + draft.getId()); + System.out.println(draft.toPrettyString()); + return draft; + } catch (GoogleJsonResponseException e) { + // TODO(developer) - handle error appropriately + System.err.println("Unable to create draft: " + e.getDetails()); + throw e; + } + } +} +// [END gmail_create_draft_with_attachment] \ No newline at end of file