Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ azure-storage-blob-application-cloudevents
azure-storage-datalake-application-cloudevents
azure-storage-queue-application-cloudevents
google-calendar-stream-application-cloudevents
google-mail-draft
google-mail-stream-application-cloudevents
google-mail-update-message-labels
google-pubsub-application-cloudevents
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"transformer": {
"kind": "transformer",
"name": "google-mail:draft",
"title": "Google Mail (Draft)",
"description": "Creates a Gmail Draft from String body and threading metadata from headers",
"deprecated": false,
"javaType": "org.apache.camel.component.google.mail.transform.GoogleMailDraftDataTypeTransformer",
"groupId": "org.apache.camel",
"artifactId": "camel-google-mail",
"version": "4.19.0-SNAPSHOT"
}
}

5 changes: 5 additions & 0 deletions components/camel-google/camel-google-mail/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@
<artifactId>commons-codec</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Generated by camel build tools - do NOT edit this file!
transformers=google-mail-stream:application-cloudevents google-mail:update-message-labels
transformers=google-mail-stream:application-cloudevents google-mail:draft google-mail:update-message-labels
groupId=org.apache.camel
artifactId=camel-google-mail
version=4.19.0-SNAPSHOT
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Generated by camel build tools - do NOT edit this file!
class=org.apache.camel.component.google.mail.transform.GoogleMailDraftDataTypeTransformer
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"transformer": {
"kind": "transformer",
"name": "google-mail:draft",
"title": "Google Mail (Draft)",
"description": "Creates a Gmail Draft from String body and threading metadata from headers",
"deprecated": false,
"javaType": "org.apache.camel.component.google.mail.transform.GoogleMailDraftDataTypeTransformer",
"groupId": "org.apache.camel",
"artifactId": "camel-google-mail",
"version": "4.19.0-SNAPSHOT"
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,165 @@ XML::
</route>
----
====
== Data Type Transformer: draft

The `google-mail:draft` transformer converts a String body into a Gmail `Draft` using mail headers from the exchange.

It works with `google-mail-stream`, which sets headers like `threadId`, `messageId`, `from`, `to`, `cc`, `bcc`, and `subject` automatically when consuming messages.
You can also set these headers manually to create drafts from scratch.

=== Headers

The transformer reads the following headers:

[cols="1,1,3"]
|===
| Header | Type | Description

| `CamelGoogleMailStreamThreadId`
| `String`
| Thread ID for the conversation (optional, used for replies)

| `CamelGoogleMailStreamMessageId`
| `String`
| Message ID to reply to (optional, sets In-Reply-To and References headers)

| `CamelGoogleMailStreamFrom`
| `String`
| From address (optional)

| `CamelGoogleMailStreamTo`
| `String`
| To address (optional)

| `CamelGoogleMailStreamCc`
| `String`
| CC address (optional)

| `CamelGoogleMailStreamBcc`
| `String`
| BCC address (optional)

| `CamelGoogleMailStreamSubject`
| `String`
| Email subject (optional)
|===

All headers are optional.

=== Message Body

The message body is a `String` with the email content (plain text or HTML).

Content type defaults to `text/plain; charset=UTF-8`. For HTML, set `Exchange.CONTENT_TYPE` to `text/html; charset=UTF-8`.

The transformer:

* Builds an RFC 2822 MIME message and encodes it as Base64 URL-safe (required by Gmail API)
* Sets `In-Reply-To` and `References` headers when `messageId` is present
* Associates the draft with the correct thread when `threadId` is present

=== Examples

[tabs]
====
Java::
+
[source,java]
----
// Create a draft reply from a received message
from("google-mail-stream:0")
.setBody(constant("Thank you for your message. I will respond soon."))
.transformDataType(new DataType("google-mail:draft"))
.to("google-mail:drafts/create?inBody=content");

// Create a new draft (no threading)
from("direct:newDraft")
.setBody(constant("This is a new draft message"))
.setHeader("CamelGoogleMailStreamFrom", constant("sender@example.com"))
.setHeader("CamelGoogleMailStreamTo", constant("recipient@example.com"))
.setHeader("CamelGoogleMailStreamSubject", constant("New Draft"))
.transformDataType(new DataType("google-mail:draft"))
.to("google-mail:drafts/create?inBody=content");
----

YAML::
+
[source,yaml]
----
# Create a draft reply from a received message
- route:
from:
uri: "google-mail-stream:0"
steps:
- setBody:
constant: "Thank you for your message. I will respond soon."
- transformDataType:
toType: "google-mail:draft"
- to:
uri: "google-mail:drafts/create"
parameters:
inBody: content

# Create a new draft (no threading)
- route:
from:
uri: "direct:newDraft"
steps:
- setBody:
constant: "This is a new draft message"
- setHeader:
name: CamelGoogleMailStreamFrom
constant: "sender@example.com"
- setHeader:
name: CamelGoogleMailStreamTo
constant: "recipient@example.com"
- setHeader:
name: CamelGoogleMailStreamSubject
constant: "New Draft"
- transformDataType:
toType: "google-mail:draft"
- to:
uri: "google-mail:drafts/create"
parameters:
inBody: content
----

XML::
+
[source,xml]
----
<!-- Create a draft reply from a received message -->
<route>
<from uri="google-mail-stream:0"/>
<setBody>
<constant>Thank you for your message. I will respond soon.</constant>
</setBody>
<transformDataType toType="google-mail:draft"/>
<to uri="google-mail:drafts/create?inBody=content"/>
</route>

<!-- Create a new draft (no threading) -->
<route>
<from uri="direct:newDraft"/>
<setBody>
<constant>This is a new draft message</constant>
</setBody>
<setHeader name="CamelGoogleMailStreamFrom">
<constant>sender@example.com</constant>
</setHeader>
<setHeader name="CamelGoogleMailStreamTo">
<constant>recipient@example.com</constant>
</setHeader>
<setHeader name="CamelGoogleMailStreamSubject">
<constant>New Draft</constant>
</setHeader>
<transformDataType toType="google-mail:draft"/>
<to uri="google-mail:drafts/create?inBody=content"/>
</route>
----
====


== More Information

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* 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.camel.component.google.mail.transform;

import java.io.ByteArrayOutputStream;
import java.util.Properties;

import jakarta.mail.Session;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;

import com.google.api.client.util.Base64;
import com.google.api.services.gmail.model.Draft;
import com.google.api.services.gmail.model.Message;
import org.apache.camel.Exchange;
import org.apache.camel.component.google.mail.stream.GoogleMailStreamConstants;
import org.apache.camel.spi.DataType;
import org.apache.camel.spi.DataTypeTransformer;
import org.apache.camel.spi.Transformer;
import org.apache.camel.util.ObjectHelper;

import static jakarta.mail.Message.RecipientType.BCC;
import static jakarta.mail.Message.RecipientType.CC;
import static jakarta.mail.Message.RecipientType.TO;

/**
* Data type transformer that builds a {@link Draft} from a String body and mail headers populated by
* google-mail-stream.
*/
@DataTypeTransformer(name = "google-mail:draft",
description = "Creates a Gmail Draft from String body and threading metadata from headers")
public class GoogleMailDraftDataTypeTransformer extends Transformer {

@Override
public void transform(org.apache.camel.Message message, DataType fromType, DataType toType) throws Exception {
String body = message.getBody(String.class);
if (ObjectHelper.isEmpty(body)) {
throw new IllegalArgumentException("Draft body must not be null or empty");
}

String threadId = message.getHeader(GoogleMailStreamConstants.MAIL_THREAD_ID, String.class);
String messageId = message.getHeader(GoogleMailStreamConstants.MAIL_MESSAGE_ID, String.class);
String from = message.getHeader(GoogleMailStreamConstants.MAIL_FROM, String.class);
String subject = message.getHeader(GoogleMailStreamConstants.MAIL_SUBJECT, String.class);
String to = message.getHeader(GoogleMailStreamConstants.MAIL_TO, String.class);
String cc = message.getHeader(GoogleMailStreamConstants.MAIL_CC, String.class);
String bcc = message.getHeader(GoogleMailStreamConstants.MAIL_BCC, String.class);

Session session = Session.getDefaultInstance(new Properties());
MimeMessage mimeMessage = new MimeMessage(session);

if (ObjectHelper.isNotEmpty(from)) {
mimeMessage.setFrom(new InternetAddress(from, true));
}
if (ObjectHelper.isNotEmpty(to)) {
mimeMessage.addRecipients(TO, InternetAddress.parse(to, true));
}
if (ObjectHelper.isNotEmpty(cc)) {
mimeMessage.addRecipients(CC, InternetAddress.parse(cc, true));
}
if (ObjectHelper.isNotEmpty(bcc)) {
mimeMessage.addRecipients(BCC, InternetAddress.parse(bcc, true));
}
if (ObjectHelper.isNotEmpty(subject)) {
mimeMessage.setSubject(subject, "UTF-8");
}

if (ObjectHelper.isNotEmpty(messageId)) {
mimeMessage.setHeader("In-Reply-To", messageId);
mimeMessage.setHeader("References", messageId);
}

String contentType = message.getHeader(Exchange.CONTENT_TYPE, String.class);
if (contentType == null) {
contentType = "text/plain; charset=UTF-8";
}
mimeMessage.setContent(body, contentType);

String encodedEmail;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
mimeMessage.writeTo(baos);
encodedEmail = Base64.encodeBase64URLSafeString(baos.toByteArray());
}

Message gmailMessage = new Message();
gmailMessage.setRaw(encodedEmail);

if (ObjectHelper.isNotEmpty(threadId)) {
gmailMessage.setThreadId(threadId);
}

Draft draft = new Draft();
draft.setMessage(gmailMessage);

message.setBody(draft);
}
}
Loading
Loading