Merge "Add the functionality to include inline attachments to EmailSender."
diff --git a/java/com/google/gerrit/server/mail/send/EmailResource.java b/java/com/google/gerrit/server/mail/send/EmailResource.java
new file mode 100644
index 0000000..169ab4b
--- /dev/null
+++ b/java/com/google/gerrit/server/mail/send/EmailResource.java
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// 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
+//
+// http://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.
+
+package com.google.gerrit.server.mail.send;
+
+import com.google.auto.value.AutoValue;
+import com.google.protobuf.ByteString;
+
+/**
+ * Email resource that can be attached to an email.
+ *
+ * <p>Can be used for images included in html body of the email.
+ */
+@AutoValue
+public abstract class EmailResource {
+  public static EmailResource create(String contentId, String contentType, ByteString content) {
+    return new AutoValue_EmailResource(contentId, contentType, content);
+  }
+
+  /** Value of Content-ID header used for referring to the resource from html body of the email. */
+  public abstract String contentId();
+
+  /** MIME type of the resource. */
+  public abstract String contentType();
+
+  /** Unencoded data that should be added to the email */
+  public abstract ByteString content();
+}
diff --git a/java/com/google/gerrit/server/mail/send/EmailSender.java b/java/com/google/gerrit/server/mail/send/EmailSender.java
index 711ab1b..51629c6 100644
--- a/java/com/google/gerrit/server/mail/send/EmailSender.java
+++ b/java/com/google/gerrit/server/mail/send/EmailSender.java
@@ -57,6 +57,34 @@
   }
 
   /**
+   * Sends an email message. Messages always contain a text body, but messages can optionally
+   * include an additional HTML body and related resources. If both body types are present, {@code
+   * send} should construct a {@code multipart/alternative} message with an appropriately-selected
+   * boundary. If the HTML Resources are provided then html body and corresponding resources should
+   * be grouped as {@code multipart/related}.
+   *
+   * @param from who the message is from.
+   * @param rcpt one or more address where the message will be delivered to. This list overrides any
+   *     To or CC headers in {@code headers}.
+   * @param headers message headers.
+   * @param textBody text to appear in the {@code text/plain} body of the message.
+   * @param htmlBody optional HTML code to appear in the {@code text/html} body of the message.
+   * @param htmlResources optional resources that can be referenced in HTML code using their {@link
+   *     EmailResource#contentId}.
+   * @throws EmailException the message cannot be sent.
+   */
+  default void send(
+      Address from,
+      Collection<Address> rcpt,
+      Map<String, EmailHeader> headers,
+      String textBody,
+      @Nullable String htmlBody,
+      Collection<EmailResource> htmlResources)
+      throws EmailException {
+    send(from, rcpt, headers, textBody, htmlBody);
+  }
+
+  /**
    * Sends an email message with a text body only (i.e. not HTML or multipart).
    *
    * <p>Authors of new implementations of this interface should not use this method to send a
diff --git a/java/com/google/gerrit/testing/FakeEmailSender.java b/java/com/google/gerrit/testing/FakeEmailSender.java
index 918a622..a2ebc88 100644
--- a/java/com/google/gerrit/testing/FakeEmailSender.java
+++ b/java/com/google/gerrit/testing/FakeEmailSender.java
@@ -26,6 +26,7 @@
 import com.google.gerrit.exceptions.EmailException;
 import com.google.gerrit.mail.MailHeader;
 import com.google.gerrit.server.git.WorkQueue;
+import com.google.gerrit.server.mail.send.EmailResource;
 import com.google.gerrit.server.mail.send.EmailSender;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
@@ -63,9 +64,15 @@
         Collection<Address> rcpt,
         Map<String, EmailHeader> headers,
         String body,
-        String htmlBody) {
+        String htmlBody,
+        Collection<EmailResource> htmlResources) {
       return new AutoValue_FakeEmailSender_Message(
-          from, ImmutableList.copyOf(rcpt), ImmutableMap.copyOf(headers), body, htmlBody);
+          from,
+          ImmutableList.copyOf(rcpt),
+          ImmutableMap.copyOf(headers),
+          body,
+          htmlBody,
+          ImmutableList.copyOf(htmlResources));
     }
 
     public abstract Address from();
@@ -78,6 +85,8 @@
 
     @Nullable
     public abstract String htmlBody();
+
+    public abstract ImmutableList<EmailResource> htmlResources();
   }
 
   private final WorkQueue workQueue;
@@ -105,7 +114,7 @@
   public void send(
       Address from, Collection<Address> rcpt, Map<String, EmailHeader> headers, String body)
       throws EmailException {
-    send(from, rcpt, headers, body, null);
+    send(from, rcpt, headers, body, null, ImmutableList.of());
   }
 
   @Override
@@ -116,7 +125,19 @@
       String body,
       String htmlBody)
       throws EmailException {
-    messages.add(Message.create(from, rcpt, headers, body, htmlBody));
+    messages.add(Message.create(from, rcpt, headers, body, htmlBody, ImmutableList.of()));
+  }
+
+  @Override
+  public void send(
+      Address from,
+      Collection<Address> rcpt,
+      Map<String, EmailHeader> headers,
+      String body,
+      String htmlBody,
+      Collection<EmailResource> htmlResources)
+      throws EmailException {
+    messages.add(Message.create(from, rcpt, headers, body, htmlBody, htmlResources));
   }
 
   public void clear() {