Skip to content

feat(email-smtp): adds custom headers (#295) - #360

Draft
mariot wants to merge 4 commits into
feature/20-create-smtpfrom
feature/20-create-smtp-mvp2-11
Draft

feat(email-smtp): adds custom headers (#295)#360
mariot wants to merge 4 commits into
feature/20-create-smtpfrom
feature/20-create-smtp-mvp2-11

Conversation

@mariot

@mariot mariot commented Jul 21, 2026

Copy link
Copy Markdown
Member

Proposed changes

Testing Instructions

  1. Step-by-step how to test
  2. Environment or config notes

Related issues

Checklist

  • I consider the submitted work as finished
  • I tested the code for its functionality
  • I wrote test cases for the relevant uses case
  • I added/update the relevant documentation (either on github or on notion)
  • Where necessary I refactored code to improve the overall quality
  • For bug fix -> I implemented a test that covers the bug

Further comments

@mariot mariot self-assigned this Jul 21, 2026
@mariot mariot added filigran team Item from the Filigran team. feature Type: new feature or capability (feat:). injector: email labels Jul 21, 2026
@mariot
mariot changed the base branch from main to feature/20-create-smtp July 21, 2026 08:56
@mariot mariot changed the title feature/20-create-smtp-mvp2-11 feat(smtp): adds custom headers (#295) Jul 21, 2026
@mariot mariot changed the title feat(smtp): adds custom headers (#295) feat(email-smtp): adds custom headers (#295) Jul 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new Email (SMTP) injector module to the OpenAEV injectors monorepo, enabling scenarios to craft and send MIME emails via SMTP (including attachments and validated custom headers). It also updates the Nuclei injector’s contract schema to include predefinedExpectations for expectations fields.

Changes:

  • Added a new email-smtp/ injector with contracts, config loading, SMTP delivery implementation, and documentation.
  • Added tests and Gherkin feature specs for payload normalization, SMTP client behavior, and contract execution flows.
  • Updated the Nuclei contract expectations field to include predefinedExpectations.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
nuclei/nuclei/nuclei_contracts/nuclei_contracts.py Adds predefinedExpectations to the expectations field definition.
email-smtp/tests/email_payload/test_email_payload.py Pytest coverage for payload normalization (ports, TLS, recipients, headers).
email-smtp/tests/email_payload/email_payload.feature Feature spec for payload building scenarios.
email-smtp/tests/email_client/test_email_client.py Pytest coverage for SMTP send behavior, attachments, and header injection handling.
email-smtp/tests/email_client/email_client.feature Feature spec for SMTP delivery scenarios.
email-smtp/tests/craft_email/test_craft_email.py Pytest coverage for contract routing, attachment download, custom headers, and callbacks.
email-smtp/tests/craft_email/craft_email.feature Feature spec for craft-email execution scenarios.
email-smtp/tests/conftest.py Pytest fixtures (config loading override + injector helper/config mocks).
email-smtp/tests/init.py Marks the tests package.
email-smtp/README.md Injector documentation (setup, configuration, behavior, contract fields).
email-smtp/pyproject.toml Package metadata, dependencies, pytest settings, and dev tooling.
email-smtp/manifest-metadata.json Injector manifest metadata for packaging/registry usage.
email-smtp/email_smtp/services/utils.py Payload builder + custom header parsing/validation utilities.
email-smtp/email_smtp/services/email_client.py SMTP client implementation for crafting/sending MIME messages.
email-smtp/email_smtp/services/init.py Re-exports service layer API.
email-smtp/email_smtp/models/exceptions.py Injector-specific exception types.
email-smtp/email_smtp/models/configs/injector_config_override.py Injector config override model (id/name/type/icon/log level).
email-smtp/email_smtp/models/configs/config_loader.py Config loader wiring OpenAEV + injector configs and contracts.
email-smtp/email_smtp/models/configs/init.py Re-exports config models.
email-smtp/email_smtp/models/init.py Re-exports models/exceptions for external imports.
email-smtp/email_smtp/injector/openaev_email_smtp.py Injector runtime: contract dispatch, attachment extraction, callbacks, logging.
email-smtp/email_smtp/injector/init.py Re-exports injector entrypoint.
email-smtp/email_smtp/contracts/email_contracts.py Contract IDs and contract registration assembly.
email-smtp/email_smtp/contracts/craft_email/contract.py Craft-email contract field definitions (SMTP + message + attachments).
email-smtp/email_smtp/contracts/craft_email/init.py Re-exports craft-email contract builder.
email-smtp/email_smtp/contracts/init.py Re-exports contracts API.
email-smtp/email_smtp/main.py Module entrypoint: load config, load icon, start helper + listener.
email-smtp/email_smtp/init.py Marks the package.
email-smtp/Dockerfile Multi-stage Docker build for the injector (with optional pyoaev override).
email-smtp/docker-compose.yml Compose service definition for running the injector.
email-smtp/config.yml.sample Sample YAML config for manual deployment.
email-smtp/.gitignore Ignores config/env/venv and caches.
email-smtp/.env.sample Sample env var configuration for Docker deployments.
email-smtp/.dockerignore Build context exclusions for smaller Docker builds.
Comments suppressed due to low confidence (4)

email-smtp/email_smtp/injector/openaev_email_smtp.py:80

  • The inline list comprehension is long and not Black-formatted; black --check . in CI is likely to reformat/fail on this file. Please wrap it over multiple lines to match the repo’s enforced formatting.
        documents = data.get("injection", {}).get("inject_documents", [])
        attachments = [doc for doc in documents if doc.get("document_attached") is True]
        if not attachments:

email-smtp/email_smtp/services/email_client.py:20

  • There’s an extra blank line at the start of the class body that violates the repo’s Black formatting (CI runs black --check .). Removing it will keep formatting consistent.
class EmailClient:

    @staticmethod
    def send_email(

email-smtp/email_smtp/services/utils.py:86

  • This mail_from expression is currently split in a way Black will rewrite (the or is outside the call’s parentheses). Reformat it to a single parenthesized expression to satisfy black --check ..
            "from": content["from"],
            "mail_from": EmailPayloadBuilder.parse_optional_email(
                content.get("mail_from")
            )
            or content["from"],
            "reply_to": EmailPayloadBuilder.parse_optional_email(

email-smtp/tests/email_client/test_email_client.py:84

  • This assertion line is long and will likely be reformatted by Black (CI runs black --check .). Consider wrapping it to avoid formatting failures.
        assert sent_message["Reply-To"] is None
        assert instance.send_message.call_args.kwargs["from_addr"] == "from@example.com"

Comment thread email-smtp/tests/craft_email/test_craft_email.py
@mariot
mariot force-pushed the feature/20-create-smtp branch from 8cb30f8 to ff55eb9 Compare July 24, 2026 08:44
mariot and others added 3 commits July 24, 2026 10:53
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@mariot
mariot force-pushed the feature/20-create-smtp-mvp2-11 branch from 0358d27 to 0c210ce Compare July 24, 2026 08:54
@mariot
mariot marked this pull request as draft July 24, 2026 09:43

@Megafredo Megafredo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Great job @mariot !
MVP2 – 10 (Adding custom headers) is functional.

I ran several tests:

✅ Adding a custom header with correct line breaks: no issues. (expected behavior)
The email header:
Image

✅ Adding a single-line custom header (without line breaks): no issues. (incorrect usage)
The email header:
Image

Tip

I think this use case deserves to be documented to facilitate its understanding and use.

✅ Case where a key or value is missing (incomplete header): an error is correctly reported. (expected behavior)
The email header:
Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Type: new feature or capability (feat:). filigran team Item from the Filigran team. injector: email

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants