> For the complete documentation index, see [llms.txt](https://docs.poja.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.poja.io/examples/hello-world-but-with-asynchronous-reply-by-email.md).

# Hello world, but with asynchronous reply by email

### Goal

We want **to add asynchronous email sending** to a [Hello World Application](https://poja.gitbook.io/poja-docs/examples/hello-world-but-straight-to-the-cloud) hosted on Poja. It exposes the `/hello?to=email@address.com` endpoint, returns `... world!`, and sends an email to the specified address.

{% hint style="info" %}
**Deploy in one click**

Before diving into the step-by-step guide, you can simply click the **Deploy to Poja** button. This will instantly deploy [this template](https://github.com/poja-app/poja-async-mailing-template) to your Poja account

<a href="https://console.poja.io/applications/create/clone/?templateId=9e25599a-cf73-4558-8697-b22273a6171b" class="button primary">Deploy to Poja</a>
{% endhint %}

### How-to in 2 steps

#### Step 1: Add email sending to your endpoint

{% code title="Java" %}

```java
package com.my.company.endpoint.rest.controller;

import com.my.company.mail.Email;
import com.my.company.mail.Mailer;
import jakarta.mail.internet.InternetAddress;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@AllArgsConstructor
public class HelloWorldController {
  private final Mailer mailer;

  @GetMapping("/hello")
  @SneakyThrows
  public String helloWorld(@RequestParam String to) {
    var email =
        new Email(
            new InternetAddress(to),
            List.of(),
            List.of(),
            "Hello",
            "... world!",
            List.of());
    mailer.accept(email);
    return "... world!";
  }
}
```

{% endcode %}

#### Step 2: Make it asynchronous

**Update the environment configuration**

Select the **preprod environment** to update. Click an **Edit** button in the **Poja Configuration** section. Then:

* Add 1 worker in the Workers section
* Click on the **Save** button at the bottom

{% hint style="info" %}
**Updating environment configuration**

When the Poja Configuration of an environment is modified:

* Changes will be **pushed on the environment’s branch** (prod or preprod)
* A new deployment will be triggered for the specified environment
  {% endhint %}

{% hint style="info" %}
Worker limits

The number of workers you can add is limited depending on your plan:

* **Basic users**: up to **2** workers
* **Premium users**: up to **10** workers
  {% endhint %}

<figure><img src="/files/TpBkwnU7h2DpyCgInG7n" alt=""><figcaption></figcaption></figure>

**Write the asynchronous code**

In the context of Poja, asychronous code refers to an Event driven code executing in Workers. Follow the instructions below to write the asynchronous email sending:

* Create the **event class** `SendEmailRequested` with the property `to` which refers to the recipient address of the email inside the package `com.my.company.endpoint.event.model`
* Create the **service** `SendEmailRequestedService` which will **consume** the event object and send the email inside the package `com.my.company.service.event`
* **Produce the event** when the user sends a request to the `/hello` endpoint and provides an email address

{% hint style="danger" %}
Important !

* Event classes **must be located** inside the `your.package.name.endpoint.event.model` package
* Event processing services **must be located** inside the `your.package.name.service.event`
* Event processing services should be named **must be named as follows** `{event_name}Service`\
  Example: `SendEmailRequested` and `SendEmailRequestedService`
  {% endhint %}

{% code title="Java" %}

```java
package com.my.company.endpoint.event.model;

import java.time.Duration;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;

@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Data
@EqualsAndHashCode(callSuper = false)
@ToString
public class SendEmailRequested extends PojaEvent {
  private String to;

  @Override
  public Duration maxConsumerDuration() {
    return Duration.ofSeconds(45);
  }

  @Override
  public Duration maxConsumerBackoffBetweenRetries() {
    return Duration.ofSeconds(30);
  }
}
```

{% endcode %}

{% code title="Java" %}

```java
package com.my.company.service.event;

import com.my.company.endpoint.event.model.SendEmailRequested;
import com.my.company.mail.Email;
import com.my.company.mail.Mailer;
import jakarta.mail.internet.InternetAddress;
import java.util.List;
import java.util.function.Consumer;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

@Service
@AllArgsConstructor
public class SendEmailRequestedService implements Consumer<SendEmailRequested> {
  private final Mailer mailer;

  @SneakyThrows
  @Override
  public void accept(SendEmailRequested sendEmailRequested) {
    var recipientAddress = new InternetAddress(sendEmailRequested.getTo());
    mailer.accept(
        new Email(
            recipientAddress,
            List.of(),
            List.of(),
            "",
            "... world!",
            List.of()));
  }
}
```

{% endcode %}

Now update the previously created `HelloWorldController` to produce an event instead of directly sending the email:

```java
package com.my.company.endpoint.rest.controller;

import com.my.company.endpoint.event.EventProducer;
import com.my.company.endpoint.event.model.SendEmailRequested;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@AllArgsConstructor
public class HelloWorldController {
  private final EventProducer<SendEmailRequested> eventProducer;

  @GetMapping("/hello")
  @SneakyThrows
  public String helloWorld(@RequestParam String to) {
    var event = SendEmailRequested.builder().to(to).build();
    eventProducer.accept(List.of(event));
    return "... world!";
  }
}
```

<i class="fa-cloud-arrow-up">:cloud-arrow-up:</i> **Deploy**

To trigger a deployment, just **commit and push** the code to the **preprod branch** of the repository. Wait. And voilà!

<div align="left"><figure><img src="/files/8BKYVrgVsm5whgTnkquX" alt="Poja Hello API endpoint returns immediately after queuing an asynchronous email event"><figcaption><p>The endpoint returns <code>... world!</code>.</p></figcaption></figure></div>

<div align="left"><figure><img src="/files/k8HP2lS0PxTxa97gn7IC" alt="Email received after asynchronous event processing by a Poja worker" width="375"><figcaption><p>The specified recipient receives the email asynchronously.</p></figcaption></figure></div>
