Skip to content

CAMEL-23258: Add google-mail:draft DataType transformer#22389

Open
zbendhiba wants to merge 3 commits intoapache:mainfrom
zbendhiba:CAMEL-23258-gmail-draft
Open

CAMEL-23258: Add google-mail:draft DataType transformer#22389
zbendhiba wants to merge 3 commits intoapache:mainfrom
zbendhiba:CAMEL-23258-gmail-draft

Conversation

@zbendhiba
Copy link
Copy Markdown
Contributor

@zbendhiba zbendhiba commented Apr 1, 2026

This code was created with the help of Claude code Fixes #CAMEL-23258

Description

Target

  • I checked that the commit is targeting the correct branch (Camel 4 uses the main branch)

Tracking

  • If this is a large change, bug fix, or code improvement, I checked there is a JIRA issue filed for the change (usually before you start working on it).

Apache Camel coding standards and style

  • I checked that each commit in the pull request has a meaningful subject line and body.
  • I have run mvn clean install -DskipTests locally from root folder and I have committed all auto-generated changes.

This code was created with the help of Claude code
Fixes #CAMEL-23258
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
Copy link
Copy Markdown
Contributor

@Croway Croway Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aren't the headers already (automatically) printed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Croway In the reply-to use case, we reuse the existing headers from the Camel exchange.
When creating a draft from scratch (a new email, not a reply-to), those headers need to be populated explicitly. However, I didn't make them mandatory. A user might want to send a message to an agent about an idea for an email via WhatsApp for example. They may not know the proper email address at that moment.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using build-all, build-dependents, skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

Copy link
Copy Markdown
Contributor

@apupier apupier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one comment to address and otherwise optional thing: a lot of places where using AssertJ assertions will allow less code and better error message in case of test failure (not marked all)

Comment on lines +90 to +91
assertTrue(decodedMessage.contains("This is a test draft message"));
assertTrue(decodedMessage.contains("Content-Type: text/plain; charset=UTF-8"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: using AssertJ assertions allows to have a better error message in case of failure. Not just only true/false but the expected text and what searched inside.

Comment on lines +111 to +115
assertTrue(decodedMessage.contains("From: sender@example.com"));
assertTrue(decodedMessage.contains("Subject: Re: Test Subject"));
assertTrue(decodedMessage.contains("In-Reply-To: <msg-456@mail.gmail.com>"));
assertTrue(decodedMessage.contains("References: <msg-456@mail.gmail.com>"));
assertTrue(decodedMessage.contains("Reply message"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: using AssertJ assertions allows to have a better error message in case of failure. Not just only true/false but the expected text and what searched inside.

These assetiosn can also be chained reducing slightly the amount of code written

Comment on lines +134 to +139
assertTrue(decodedMessage.contains("From: from@example.com"));
assertTrue(decodedMessage.contains("To: to@example.com"));
assertTrue(decodedMessage.contains("Cc: cc@example.com"));
assertTrue(decodedMessage.contains("Bcc: bcc@example.com"));
assertTrue(decodedMessage.contains("Subject: Complete Test"));
assertTrue(decodedMessage.contains("Complete message"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: using AssertJ assertions allows to have a better error message in case of failure. Not just only true/false but the expected text and what searched inside.

These assetiosn can also be chained reducing slightly the amount of code written

assertNotNull(draft.getMessage().getRaw());

String decodedMessage = decodeMessage(draft.getMessage().getRaw());
assertTrue(decodedMessage.contains("Subject: Empty Body Test"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: using AssertJ assertions allows to have a better error message in case of failure. Not just only true/false but the expected text and what searched inside.


Draft draft = exchange.getMessage().getBody(Draft.class);
assertNotNull(draft);
assertNotNull(draft.getMessage().getRaw());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it normal that we do not have a null body if we set a null body?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@apupier Good point. I'll make the body mandatory. A draft without a body doesn't make much sense.


String decodedMessage = decodeMessage(draft.getMessage().getRaw());
// Without explicit Content-Type header, defaults to text/plain even for HTML-like body
assertTrue(decodedMessage.contains("text/plain"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: using AssertJ assertions allows to have a better error message in case of failure. Not just only true/false but the expected text and what searched inside.

assertNotNull(draft);

String decodedMessage = decodeMessage(draft.getMessage().getRaw());
// Without explicit Content-Type header, defaults to text/plain even for HTML-like body
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment will be better placed directly in the error message of the assertion so that when it fails we directly understand what was looked for and why.

Also better chance that it is kept in sync with the code if it is not a comment

Comment on lines +219 to +220
assertTrue(decodedMessage.contains("text/html"));
assertTrue(decodedMessage.contains(htmlBody));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: using AssertJ assertions allows to have a better error message in case of failure. Not just only true/false but the expected text and what searched inside.

// Verify that the non-ASCII characters are preserved after decoding
String decodedSubject = MimeUtility.decodeText(
decodedMessage.lines().filter(l -> l.startsWith("Subject:")).findFirst().orElse(""));
assertNotEquals("", decodedSubject);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check is not useful given that the next assertions is checking more precisely and will cover the case of empty string

@zbendhiba
Copy link
Copy Markdown
Contributor Author

@apupier I've addressed most of your comments in my new commits

@zbendhiba zbendhiba requested review from Croway and apupier April 2, 2026 08:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants