SLING-8545 - Mails are missing proper date header

* extracted email templates to separate files and added Date header
diff --git a/pom.xml b/pom.xml
index 0e21a19..4a00263 100644
--- a/pom.xml
+++ b/pom.xml
@@ -167,6 +167,15 @@
                     <skip>true</skip>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>src/main/resources/templates/*</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 
@@ -236,6 +245,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
         </dependency>
diff --git a/src/main/features/app.json b/src/main/features/app.json
index 739d561..aee3a84 100644
--- a/src/main/features/app.json
+++ b/src/main/features/app.json
@@ -73,6 +73,9 @@
         },
         {
             "id": "info.picocli:picocli:4.0.0-beta-2"
+        },
+        {
+            "id": "commons-io:commons-io:2.6"
         }
     ]
 }
diff --git a/src/main/java/org/apache/sling/cli/impl/DateProvider.java b/src/main/java/org/apache/sling/cli/impl/DateProvider.java
new file mode 100644
index 0000000..627cca8
--- /dev/null
+++ b/src/main/java/org/apache/sling/cli/impl/DateProvider.java
@@ -0,0 +1,40 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you 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 org.apache.sling.cli.impl;
+
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+
+import org.osgi.service.component.annotations.Component;
+
+@Component(service = DateProvider.class)
+public class DateProvider {
+
+    private static final DateTimeFormatter emailDateHeader = DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss Z");
+
+    public OffsetDateTime getCurrentDate() {
+        return OffsetDateTime.now();
+    }
+
+    public String getCurrentDateForEmailHeader() {
+        OffsetDateTime offsetDateTime = OffsetDateTime.now();
+        return offsetDateTime.format(emailDateHeader);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/cli/impl/release/PrepareVoteEmailCommand.java b/src/main/java/org/apache/sling/cli/impl/release/PrepareVoteEmailCommand.java
index 99dbb96..6a416c6 100644
--- a/src/main/java/org/apache/sling/cli/impl/release/PrepareVoteEmailCommand.java
+++ b/src/main/java/org/apache/sling/cli/impl/release/PrepareVoteEmailCommand.java
@@ -17,12 +17,15 @@
 package org.apache.sling.cli.impl.release;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.stream.Collectors;
 
 import javax.mail.internet.InternetAddress;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.sling.cli.impl.Command;
+import org.apache.sling.cli.impl.DateProvider;
 import org.apache.sling.cli.impl.InputOption;
 import org.apache.sling.cli.impl.UserInput;
 import org.apache.sling.cli.impl.jira.Version;
@@ -69,6 +72,9 @@
     @Reference
     private Mailer mailer;
 
+    @Reference
+    private DateProvider dateProvider;
+
     @CommandLine.Option(names = {"-r", "--repository"}, description = "Nexus repository id", required = true)
     private Integer repositoryId;
 
@@ -76,39 +82,20 @@
     private ReusableCLIOptions reusableCLIOptions;
 
     @CommandLine.Spec
-    CommandLine.Model.CommandSpec spec;
+    private CommandLine.Model.CommandSpec spec;
 
-    // TODO - replace with file template
-    private static final String EMAIL_TEMPLATE =
-            "From: ##FROM##\n" +
-            "To: \"Sling Developers List\" <dev@sling.apache.org>\n" +
-            "Subject: [VOTE] Release ##RELEASE_NAME##\n" + 
-            "\n" + 
-            "Hi,\n" + 
-            "\n" + 
-            "We solved ##FIXED_ISSUES_COUNT## issue(s) in ##RELEASE_OR_RELEASES##:\n" +
-            "##RELEASE_JIRA_LINKS##\n" +
-            "\n" +
-            "Staging repository:\n" +
-            "https://repository.apache.org/content/repositories/orgapachesling-##RELEASE_ID##/\n" +
-            "\n" +
-            "You can use this UNIX script to download the release and verify the signatures:\n" +
-            "https://gitbox.apache.org/repos/asf?p=sling-tooling-release.git;a=blob;f=check_staged_release.sh;hb=HEAD\n" +
-            "\n" +
-            "Usage:\n" +
-            "sh check_staged_release.sh ##RELEASE_ID## /tmp/sling-staging\n" +
-            "\n" +
-            "Please vote to approve this release:\n" +
-            "\n" +
-            "  [ ] +1 Approve the release\n" +
-            "  [ ]  0 Don't care\n" +
-            "  [ ] -1 Don't release, because ...\n" +
-            "\n" +
-            "This majority vote is open for at least 72 hours.\n" +
-            "\n" +
-            "Regards,\n" +
-            "##USER_NAME##\n" +
-            "\n";
+    private static final String EMAIL_TEMPLATE;
+
+    static {
+        try {
+            EMAIL_TEMPLATE = IOUtils.toString(
+                    PrepareVoteEmailCommand.class.getClassLoader().getResourceAsStream("templates/release.email"),
+                    StandardCharsets.UTF_8
+            );
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to read embedded email template.", e);
+        }
+    }
 
     private static final String RELEASE_TEMPLATE =
             "https://issues.apache.org/jira/browse/SLING/fixforversion/##VERSION_ID##";
@@ -141,6 +128,7 @@
                 Member currentMember = membersFinder.getCurrentMember();
                 String emailContents = EMAIL_TEMPLATE
                         .replace("##FROM##", new InternetAddress(currentMember.getEmail(), currentMember.getName()).toString())
+                        .replace("##DATE##", dateProvider.getCurrentDateForEmailHeader())
                         .replace("##RELEASE_NAME##", releaseName)
                         .replace("##RELEASE_ID##", String.valueOf(repositoryId))
                         .replace("##RELEASE_OR_RELEASES##", releaseOrReleases)
diff --git a/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java b/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java
index 8235819..5ca49f2 100644
--- a/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java
+++ b/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java
@@ -17,6 +17,7 @@
 package org.apache.sling.cli.impl.release;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.text.Collator;
 import java.util.Arrays;
 import java.util.LinkedHashSet;
@@ -27,7 +28,9 @@
 
 import javax.mail.internet.InternetAddress;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.sling.cli.impl.Command;
+import org.apache.sling.cli.impl.DateProvider;
 import org.apache.sling.cli.impl.InputOption;
 import org.apache.sling.cli.impl.UserInput;
 import org.apache.sling.cli.impl.mail.Email;
@@ -70,31 +73,27 @@
     @Reference
     private Mailer mailer;
 
+    @Reference
+    private DateProvider dateProvider;
+
     @CommandLine.Option(names = {"-r", "--repository"}, description = "Nexus repository id", required = true)
     private Integer repositoryId;
 
     @CommandLine.Mixin
     private ReusableCLIOptions reusableCLIOptions;
 
-    // TODO - move to file
-    private static final String EMAIL_TEMPLATE =
-            "From: ##FROM## \n" +
-            "To: \"Sling Developers List\" <dev@sling.apache.org>\n" + 
-            "Subject: [RESULT] [VOTE] Release ##RELEASE_NAME##\n" + 
-            "\n" + 
-            "Hi,\n" + 
-            "\n" + 
-            "The vote has passed with the following result:\n" +
-            "\n" + 
-            "+1 (binding): ##BINDING_VOTERS##\n" + 
-            "+1 (non-binding): ##NON_BINDING_VOTERS##\n" +
-            "\n" +
-            "I will copy this release to the Sling dist directory and\n" + 
-            "promote the artifacts to the central Maven repository.\n" +
-            "\n" +
-            "Regards,\n" +
-            "##USER_NAME##\n" +
-            "\n";
+    private static final String EMAIL_TEMPLATE;
+
+    static {
+        try {
+            EMAIL_TEMPLATE = IOUtils.toString(
+                    TallyVotesCommand.class.getClassLoader().getResourceAsStream("templates/tally-votes.email"),
+                    StandardCharsets.UTF_8
+            );
+        } catch (IOException e) {
+            throw new IllegalStateException("Unable to read embedded email template.", e);
+        }
+    }
 
     @Override
     public void run() {
@@ -130,6 +129,7 @@
                 Member currentMember = membersFinder.getCurrentMember();
                 String email = EMAIL_TEMPLATE
                         .replace("##FROM##", new InternetAddress(currentMember.getEmail(), currentMember.getName()).toUnicodeString())
+                        .replace("##DATE##", dateProvider.getCurrentDateForEmailHeader())
                         .replace("##RELEASE_NAME##", releaseFullName)
                         .replace("##BINDING_VOTERS##", String.join(", ", bindingVoters))
                         .replace("##USER_NAME##", membersFinder.getCurrentMember().getName());
diff --git a/src/main/resources/templates/release.email b/src/main/resources/templates/release.email
new file mode 100644
index 0000000..235d9fa
--- /dev/null
+++ b/src/main/resources/templates/release.email
@@ -0,0 +1,30 @@
+From: ##FROM##
+To: "Sling Developers List" <dev@sling.apache.org>
+Reply-To: "Sling Developers List" <dev@sling.apache.org>
+Date: ##DATE##
+Subject: [VOTE] Release ##RELEASE_NAME##
+
+Hi,
+
+We solved ##FIXED_ISSUES_COUNT## issue(s) in ##RELEASE_OR_RELEASES##:
+##RELEASE_JIRA_LINKS##
+
+Staging repository:
+https://repository.apache.org/content/repositories/orgapachesling-##RELEASE_ID##/
+
+You can use this UNIX script to download the release and verify the signatures:
+https://gitbox.apache.org/repos/asf?p=sling-tooling-release.git;a=blob;f=check_staged_release.sh;hb=HEAD
+
+Usage:
+sh check_staged_release.sh ##RELEASE_ID## /tmp/sling-staging
+
+Please vote to approve this release:
+
+  [ ] +1 Approve the release
+  [ ]  0 Don't care
+  [ ] -1 Don't release, because ...
+
+This majority vote is open for at least 72 hours.
+
+Regards,
+##USER_NAME##
diff --git a/src/main/resources/templates/tally-votes.email b/src/main/resources/templates/tally-votes.email
new file mode 100644
index 0000000..af68d64
--- /dev/null
+++ b/src/main/resources/templates/tally-votes.email
@@ -0,0 +1,18 @@
+From: ##FROM##
+To: "Sling Developers List" <dev@sling.apache.org>
+Reply-To: "Sling Developers List" <dev@sling.apache.org>
+Date: ##DATE##
+Subject: [RESULT] [VOTE] Release ##RELEASE_NAME##
+
+Hi,
+
+The vote has passed with the following result:
+
++1 (binding): ##BINDING_VOTERS##
++1 (non-binding): ##NON_BINDING_VOTERS##
+
+I will copy this release to the Sling dist directory and
+promote the artifacts to the central Maven repository.
+
+Regards,
+##USER_NAME##
diff --git a/src/test/java/org/apache/sling/cli/impl/release/PrepareVoteEmailCommandTest.java b/src/test/java/org/apache/sling/cli/impl/release/PrepareVoteEmailCommandTest.java
index e408509..728cd98 100644
--- a/src/test/java/org/apache/sling/cli/impl/release/PrepareVoteEmailCommandTest.java
+++ b/src/test/java/org/apache/sling/cli/impl/release/PrepareVoteEmailCommandTest.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 
 import org.apache.sling.cli.impl.Command;
+import org.apache.sling.cli.impl.DateProvider;
 import org.apache.sling.cli.impl.ExecutionMode;
 import org.apache.sling.cli.impl.jira.Version;
 import org.apache.sling.cli.impl.jira.VersionClient;
@@ -70,6 +71,8 @@
         verify(mailer).send(
                 "From: John Doe <johndoe@apache.org>\n" +
                         "To: \"Sling Developers List\" <dev@sling.apache.org>\n" +
+                        "Reply-To: \"Sling Developers List\" <dev@sling.apache.org>\n" +
+                        "Date: Thu, 1 Jan 1970 01:00:00 +0100\n" +
                         "Subject: [VOTE] Release Apache Sling CLI Test 1.0.0\n" +
                         "\n" +
                         "Hi,\n" +
@@ -95,8 +98,7 @@
                         "This majority vote is open for at least 72 hours.\n" +
                         "\n" +
                         "Regards,\n" +
-                        "John Doe\n" +
-                        "\n");
+                        "John Doe\n");
     }
 
     private void prepareExecution(Mailer mailer) throws IOException {
@@ -115,6 +117,10 @@
         when(version.getIssuesFixedCount()).thenReturn(42);
         when(versionClient.find(Release.fromString("CLI Test 1.0.0").get(0))).thenReturn(version);
 
+        DateProvider dateProvider = mock(DateProvider.class);
+        when(dateProvider.getCurrentDateForEmailHeader()).thenReturn("Thu, 1 Jan 1970 01:00:00 +0100");
+        osgiContext.registerService(DateProvider.class, dateProvider);
+
         osgiContext.registerService(MembersFinder.class, membersFinder);
         osgiContext.registerService(StagingRepositoryFinder.class, stagingRepositoryFinder);
         osgiContext.registerService(VersionClient.class, versionClient);
diff --git a/src/test/java/org/apache/sling/cli/impl/release/TallyVotesCommandTest.java b/src/test/java/org/apache/sling/cli/impl/release/TallyVotesCommandTest.java
index c61cc7f..6583e05 100644
--- a/src/test/java/org/apache/sling/cli/impl/release/TallyVotesCommandTest.java
+++ b/src/test/java/org/apache/sling/cli/impl/release/TallyVotesCommandTest.java
@@ -29,6 +29,7 @@
 import org.apache.sling.cli.impl.Command;
 import org.apache.sling.cli.impl.Credentials;
 import org.apache.sling.cli.impl.CredentialsService;
+import org.apache.sling.cli.impl.DateProvider;
 import org.apache.sling.cli.impl.ExecutionMode;
 import org.apache.sling.cli.impl.mail.Email;
 import org.apache.sling.cli.impl.mail.Mailer;
@@ -38,6 +39,7 @@
 import org.apache.sling.cli.impl.people.Member;
 import org.apache.sling.cli.impl.people.MembersFinder;
 import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -63,6 +65,14 @@
                          "org.w3c.dom.*"
                  })
 public class TallyVotesCommandTest {
+
+    @Before
+    public void beforeClass() {
+        DateProvider dateProvider = mock(DateProvider.class);
+        when(dateProvider.getCurrentDateForEmailHeader()).thenReturn("Thu, 1 Jan 1970 01:00:00 +0100");
+        osgiContext.registerService(DateProvider.class, dateProvider);
+    }
+
     @Rule
     public final OsgiContext osgiContext = new OsgiContext();
 
@@ -92,8 +102,10 @@
         Command command = (Command) osgiContext.bundleContext().getService(reference);
         command.run();
         verify(logger).info(
-                "From: John Doe <johndoe@apache.org> \n" +
+                "From: John Doe <johndoe@apache.org>\n" +
                 "To: \"Sling Developers List\" <dev@sling.apache.org>\n" +
+                "Reply-To: \"Sling Developers List\" <dev@sling.apache.org>\n" +
+                "Date: Thu, 1 Jan 1970 01:00:00 +0100\n" +
                 "Subject: [RESULT] [VOTE] Release Apache Sling CLI Test 1.0.0\n" +
                 "\n" +
                 "Hi,\n" +
@@ -107,8 +119,7 @@
                 "promote the artifacts to the central Maven repository.\n" +
                 "\n" +
                 "Regards,\n" +
-                "John Doe\n" +
-                "\n"
+                "John Doe\n"
         );
     }
 
@@ -165,8 +176,10 @@
         Command command = (Command) osgiContext.bundleContext().getService(reference);
         command.run();
         verify(mailer).send(
-                "From: John Doe <johndoe@apache.org> \n" +
+                "From: John Doe <johndoe@apache.org>\n" +
                         "To: \"Sling Developers List\" <dev@sling.apache.org>\n" +
+                        "Reply-To: \"Sling Developers List\" <dev@sling.apache.org>\n" +
+                        "Date: Thu, 1 Jan 1970 01:00:00 +0100\n" +
                         "Subject: [RESULT] [VOTE] Release Apache Sling CLI Test 1.0.0\n" +
                         "\n" +
                         "Hi,\n" +
@@ -180,8 +193,7 @@
                         "promote the artifacts to the central Maven repository.\n" +
                         "\n" +
                         "Regards,\n" +
-                        "John Doe\n" +
-                        "\n"
+                        "John Doe\n"
         );
     }