public class Attachment extends BaseModel {
    /**
     * Unique identifier for the attachment.
     */
    @Key
    private String id;

    /**
     * The MIME type of the attachment.
     */
    @Key
    private String contentType;

    /**
     * The filename of the attachment.
     */
    @Key
    private String fileName;

    /**
     * The base64-encoded content of the attachment. Note: This is only populated when sending attachments.
     */
    @Key
    private String content;

    /**
     * The content identifier (for attachments that are embedded within the body of the message).
     */
    @Key
    private String contentId;

    /**
     * The file size, in bytes.
     */
    @Key
    private Long length;

    /**
     * Gets the unique identifier for the attachment.
     *
     * @return Attachment ID.
     */
    public String id() {
        return this.id;
    }

    /**
     * Gets the MIME type of the attachment.
     * @return Attachment MIME type.
     */
    public String contentType() {
        return nullableString(this.contentType);
    }

    /**
     * Sets the MIME type of the attachment.
     *
     * @param contentType MIME type.
     * @return the Attachment object itself.
     */
    public Attachment withContentType(String contentType) {
        this.contentType = contentType;
        return this;
    }

    /**
     * Gets the filename of the attachment.
     */
    public String fileName() {
        return nullableString(this.fileName);
    }

    /**
     * Sets the filename of the attachment.
     *
     * @param fileName Attachment filename.
     * @return the Attachment object itself.
     */
    public Attachment withFileName(String fileName) {
        this.fileName = fileName;
        return this;
    }

    /**
     * Gets the base64-encoded content of the attachment. Note: This is only populated when sending attachments.
     *
     * @return The base64-encoded content of the attachment.
     */
    public String content() {
        return nullableString(this.content);
    }

    /**
     * Sets the base64-encoded content of the attachment.
     *
     * @param content Base64-encoded content of the attachment.
     * @return the Attachment object itself.
     */
    public Attachment withContent(String content) {
        this.content = content;
        return this;
    }

    /**
     * Gets the content identifier (for attachments that are embedded within the body of the message).
     *
     * @return The content identifier
     */
    public String contentId() {
        return nullableString(this.contentId);
    }

    /**
     * Sets the content identifier (for attachments that are embedded within the body of the message).
     *
     * @param contentId The content identifier.
     * @return the Attachment object itself.
     */
    public Attachment withContentId(String contentId) {
        this.contentId = contentId;
        return this;
    }

    /**
     * Gets the file size, in bytes.
     *
     * @return The file size, in bytes.
     */
    public Long length() {
        return this.length;
    }
} public class MessageHeader extends BaseModel {
    /**
     * Header key.
     */
	@Key
    private String field;

    /**
     * Header value.
     */
	@Key
    private String value;

    /**
     * Gets the header key.
     *
     * @return The header key.
     */
    public String field() {
        return nullableString(this.field);
    }

    /**
     * Gets the header value.
     *
     * @return The header value.
     */
    public String value() {
        return nullableString(this.value);
    }
} public class Message extends BaseModel {
    public Message() { }

    /**
     * This constructor used for Mailosaur library tests only
     */
    public Message(List<MessageAddress> from, List<MessageAddress> to, String subject, String server, DateTime received) {
        this.from = from;
        this.to = to;
        this.subject = subject;
        this.server = server;
        this.received = received;
    }

    /**
     * Unique identifier for the message.
     */
    @Key
    private String id;

    /**
     * The sender of the message.
     */
    @Key
    private List<MessageAddress> from;

    /**
     * The recipients of the message.
     */
    @Key
    private List<MessageAddress> to;

    /**
     * Carbon-copied recipients for email messages.
     */
    @Key
    private List<MessageAddress> cc;

    /**
     * Blind carbon-copied recipients for email messages.
     */
    @Key
    private List<MessageAddress> bcc;

    /**
     * The date/time that this message was received by Mailosaur.
     */
    @Key
    private DateTime received;

    /**
     * The subject of the message.
     */
    @Key
    private String subject;

    /**
     * Message content that was sent in HTML format.
     */
    @Key
    private MessageContent html;

    /**
     * Message content that was sent in plain text format.
     */
    @Key
    private MessageContent text;

    /**
     * An array of attachment metadata for any attached files.
     */
    @Key
    private List<Attachment> attachments;

    /**
     * Further metadata related to the message, including email headers.
     */
    @Key
    private Metadata metadata;

    /**
     * Identifier for the server in which the message is located.
     */
    @Key
    private String server;

    /**
     * Gets the unique identifier for the message.
     *
     * @return The unique identifier for the message.
     */
    public String id() {
        return this.id;
    }

    /**
     * Gets the sender of the message.
     *
     * @return The sender of the message.
     */
    public List<MessageAddress> from() {
        return this.from;
    }

    /**
     * Gets the recipients of the message.
     *
     * @return The recipients of the message.
     */
    public List<MessageAddress> to() {
        return this.to;
    }

    /**
     * Gets the carbon-copied recipients for email messages.
     *
     * @return Carbon-copied recipients for email messages.
     */
    public List<MessageAddress> cc() {
        return this.cc;
    }

    /**
     * Gets the blind carbon-copied recipients for email messages.
     *
     * @return Blind carbon-copied recipients for email messages.
     */
    public List<MessageAddress> bcc() {
        return this.bcc;
    }

    /**
     * Gets the date/time that this message was received by Mailosaur.
     *
     * @return The date/time that this message was received by Mailosaur.
     */
    public DateTime received() {
        return this.received;
    }

    /**
     * Gets the subject of the message.
     *
     * @return The subject of the message.
     */
    public String subject() {
        return nullableString(this.subject);
    }

    /**
     * Gets the message content that was sent in HTML format.
     *
     * @return Message content that was sent in HTML format.
     */
    public MessageContent html() {
        return this.html;
    }

    /**
     * Gets the message content that was sent in plain text format.
     *
     * @return Message content that was sent in plain text format.
     */
    public MessageContent text() {
        return this.text;
    }

    /**
     * Gets an array of attachment metadata for any attached files.
     *
     * @return An array of attachment metadata for any attached files.
     */
    public List<Attachment> attachments() {
        return this.attachments;
    }

    /**
     * Gets further metadata related to the message, including email headers.
     *
     * @return Further metadata related to the message, including email headers.
     */
    public Metadata metadata() {
        return this.metadata;
    }

    /**
     * Gets the identifier for the server in which the message is located.
     *
     * @return Identifier for the server in which the message is located.
     */
    public String server() {
        return this.server;
    }
    
} public class MessageSummary extends BaseModel {
    /**
     * Unique identifier for the message.
     */
    @Key
    private String id;

    /**
     * The sender of the message.
     */
    @Key
    private List<MessageAddress> from;

    /**
     * The recipients of the message.
     */
    @Key
    private List<MessageAddress> to;

    /**
     * Carbon-copied recipients for email messages.
     */
    @Key
    private List<MessageAddress> cc;

    /**
     * Blind carbon-copied recipients for email messages.
     */
    @Key
    private List<MessageAddress> bcc;

    /**
     * The date/time that this message was received by Mailosaur.
     */
    @Key
    private DateTime received;

    /**
     * The subject of the message.
     */
    @Key
    private String subject;

    /**
     * A short, summarized version of the message content.
     */
	@Key
    private String summary;

    /**
     * The number of attachments associated with the message.
     */
	@Key
    private Integer attachments;

    /**
     * Identifier for the server in which the message is located.
     */
    @Key
    private String server;

    /**
     * Get the unique identifier for the message.
     *
     * @return Unique identifier for the message.
     */
    public String id() {
        return this.id;
    }

    /**
     * Gets the sender of the message.
     *
     * @return The sender of the message.
     */
    public List<MessageAddress> from() {
        return this.from;
    }

    /**
     * Gets the recipients of the message.
     *
     * @return The recipients of the message.
     */
    public List<MessageAddress> to() {
        return this.to;
    }

    /**
     * Gets the carbon-copied recipients for email messages.
     *
     * @return The carbon-copied recipients for email messages.
     */
    public List<MessageAddress> cc() {
        return this.cc;
    }

    /**
     * Gets the blind carbon-copied recipients for email messages.
     *
     * @return The blind carbon-copied recipients for email messages.
     */
    public List<MessageAddress> bcc() {
        return this.bcc;
    }

    /**
     * Gets the date/time that this message was received by Mailosaur.
     *
     * @return The date/time that this message was received by Mailosaur.
     */
    public DateTime received() {
        return this.received;
    }

    /**
     * Gets the subject of the message.
     *
     * @return The subject of the message.
     */
    public String subject() {
        return nullableString(this.subject);
    }

    /**
     * Gets a short, summarized version of the message content.
     *
     * @return A short, summarized version of the message content.
     */
    public String summary() {
        return nullableString(this.summary);
    }

    /**
     * Gets the number of attachments associated with the message.
     *
     * @return The number of attachments associated with the message.
     */
    public Integer attachments() {
        return this.attachments;
    }

    /**
     * Gets the identifier for the server in which the message is located.
     *
     * @return Identifier for the server in which the message is located.
     */
    public String server() {
        return this.server;
    }

} public class SearchCriteria {
    /**
     * The full email address (or phone number for SMS) from which the target message was sent.
     */
	@Key
    private String sentFrom;

    /**
     * The full email address (or phone number for SMS) to which the target message was sent.
     */
	@Key
    private String sentTo;

    /**
     * The value to seek within the subject line of a target email.
     */
	@Key
    private String subject;

    /**
     * The value to seek within the body of the target message.
     */
	@Key
    private String body;

    /**
     * If set to `ALL` (default), then only results that match all specified criteria will be returned.
     * If set to `ANY`, results that match any of the specified criteria will be returned.
     */
	@Key
    private SearchMatchOperator match;

    /**
     * Sets the full email address (or phone number for SMS) from which the target message was sent.
     *
     * @param sentFrom Email address (or phone number for SMS).
     * @return the SearchCriteria object itself.
     */
    public SearchCriteria withSentFrom(String sentFrom) {
        this.sentFrom = sentFrom;
        return this;
    }

    /**
     * Sets the full email address (or phone number for SMS) to which the target message was sent.
     *
     * @param sentTo Email address (or phone number for SMS).
     * @return the SearchCriteria object itself.
     */
    public SearchCriteria withSentTo(String sentTo) {
        this.sentTo = sentTo;
        return this;
    }

    /**
     * Sets the value to seek within the subject line of a target email.
     *
     * @param subject The value to seek within the subject line of a target email.
     * @return the SearchCriteria object itself.
     */
    public SearchCriteria withSubject(String subject) {
        this.subject = subject;
        return this;
    }

    /**
     * Sets the value to seek within the body of the target message.
     *
     * @param body The value to seek within the body of the target message.
     * @return the SearchCriteria object itself.
     */
    public SearchCriteria withBody(String body) {
        this.body = body;
        return this;
    }

    /**
     * If set to `ALL` (default), then only results that match all specified criteria will be returned.
     * If set to `ANY`, results that match any of the specified criteria will be returned.
     *
     * @param match Match `ALL` or `ANY` of the specified criteria.
     * @return the SearchCriteria object itself.
     */
    public SearchCriteria withMatch(SearchMatchOperator match) {
        this.match = match;
        return this;
    }
} public enum SearchMatchOperator {
    @Value("ALL")
    ALL,
    @Value("ANY")
    ANY
} public class SpamAssassinRule {
    /**
     * Spam Assassin rule score.
     */
	@Key
    private Double score;

    /**
     * Spam Assassin rule name.
     */
	@Key
    private String rule;

    /**
     * Spam Assassin rule description.
     */
	@Key
    private String description;

    /**
     * Gets the Spam Assassin rule score.
     *
     * @return The Spam Assassin rule score.
     */
    public Double score() {
        return this.score;
    }

    /**
     * Gets the Spam Assassin rule name.
     *
     * @return The Spam Assassin rule name.
     */
    public String rule() {
        return this.rule;
    }

    /**
     * Gets the Spam Assassin rule description.
     *
     * @return The Spam Assassin rule description.
     */
    public String description() {
        return this.description;
    }

} public class SpamAnalysisResult {
    /**
     * Spam filter results.
     */
    @Key
    private SpamFilterResults spamFilterResults;

    /**
     * Overall Mailosaur spam score.
     */
    @Key
    private Double score;

    /**
     * Gets the Spam filter results.
     *
     * @return Spam filter results.
     */
    public SpamFilterResults spamFilterResults() {
        return this.spamFilterResults;
    }
    
    /**
     * Gets the overall Mailosaur spam score.
     *
     * @return The overall Mailosaur spam score.
     */
    public Double score() {
        return this.score;
    }

} public class MessageCreateOptions {
    /**
     * The email address to which the email will be sent. Must be a verified email address.
     */
	@Key
    private String to;

    /**
     * If true, email will be sent upon creation.
     */
	@Key
    private Boolean send;

    /**
     * The email subject line.
     */
	@Key
    private String subject;

    /**
     * The plain text body of the message. Note that only text or html can be supplied, not both.
     */
	@Key
    private String text;

    /**
     * The HTML body of the message. Note that only text or html can be supplied, not both.
     */
	@Key
    private String html;

    /**
     * Any message attachments.
     */
    @Key
    private List<Attachment> attachments;

    /**
     * Sets the email address to which the email will be sent. Must be a verified email address.
     *
     * @param to The email address.
     * @return the MessageCreateOptions object itself.
     */
    public MessageCreateOptions withTo(String to) {
        this.to = to;
        return this;
    }

    /**
     * Sets whether the email should be sent upon creation.
     *
     * @param send If true, email will be sent upon creation.
     * @return the MessageCreateOptions object itself.
     */
    public MessageCreateOptions withSend(Boolean send) {
        this.send = send;
        return this;
    }

    /**
     * Sets the email subject line.
     *
     * @param subject The email subject line.
     * @return the MessageCreateOptions object itself.
     */
    public MessageCreateOptions withSubject(String subject) {
        this.subject = subject;
        return this;
    }

    /**
     * Sets any plain text to include when forwarding the message. Note that only text or html can be supplied, not both.
     *
     * @param text Plain text content to include when forwarding the message.
     * @return the MessageCreateOptions object itself.
     */
    public MessageCreateOptions withText(String text) {
        this.text = text;
        return this;
    }

    /**
     * Sets any HTML content to include when forwarding the message. Note that only text or html can be supplied, not both.
     *
     * @param html HTML content to include when forwarding the message.
     * @return the MessageCreateOptions object itself.
     */
    public MessageCreateOptions withHtml(String html) {
        this.html = html;
        return this;
    }

    /**
     * Sets any message attachments.
     *
     * @param attachments Any message attachments.
     * @return the MessageCreateOptions object itself.
     */
    public MessageCreateOptions withAttachments(List<Attachment> attachments) {
        this.attachments = attachments;
        return this;
    }
} public class MessageForwardOptions {
    /**
     * The email address to which the email will be sent. Must be a verified email address.
     */
	@Key
    private String to;

    /**
     * Any plain text to include when forwarding the message. Note that only text or html can be supplied, not both.
     */
	@Key
    private String text;

    /**
     * Any HTML content to include when forwarding the message. Note that only text or html can be supplied, not both.
     */
	@Key
    private String html;

    /**
     * Sets the email address to which the email will be sent. Must be a verified email address.
     *
     * @param to The email address.
     * @return the MessageForwardOptions object itself.
     */
    public MessageForwardOptions withTo(String to) {
        this.to = to;
        return this;
    }

    /**
     * Sets any plain text to include when forwarding the message. Note that only text or html can be supplied, not both.
     *
     * @param text Plain text content to include when forwarding the message.
     * @return the MessageForwardOptions object itself.
     */
    public MessageForwardOptions withText(String text) {
        this.text = text;
        return this;
    }

    /**
     * Sets any HTML content to include when forwarding the message. Note that only text or html can be supplied, not both.
     *
     * @param html HTML content to include when forwarding the message.
     * @return the MessageForwardOptions object itself.
     */
    public MessageForwardOptions withHtml(String html) {
        this.html = html;
        return this;
    }
} public class MessageReplyOptions {
    /**
     * Any additional plain text content to include in the reply. Note that only text or html can be supplied, not both.
     */
	@Key
    private String text;

    /**
     * Any additional HTML content to include in the reply. Note that only html or text can be supplied, not both.
     */
	@Key
    private String html;

    /**
     * Any message attachments.
     */
    @Key
    private List<Attachment> attachments;

    /**
     * Sets any additional plain text content to include in the reply. Note that only text or html can be supplied, not both.
     *
     * @param text Plain text content to include in the reply.
     * @return the MessageReplyOptions object itself.
     */
    public MessageReplyOptions withText(String text) {
        this.text = text;
        return this;
    }

    /**
     * Sets any additional HTML content to include in the reply. Note that only html or text can be supplied, not both.
     *
     * @param html HTML content to include in the reply.
     * @return the MessageReplyOptions object itself.
     */
    public MessageReplyOptions withHtml(String html) {
        this.html = html;
        return this;
    }

    /**
     * Sets any message attachments.
     *
     * @param attachments Any message attachments.
     * @return the MessageReplyOptions object itself.
     */
    public MessageReplyOptions withAttachments(List<Attachment> attachments) {
        this.attachments = attachments;
        return this;
    }
}
import static org.junit.Assert.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.*;
import java.util.stream.Stream;
import javax.mail.MessagingException;
import org.junit.BeforeClass;
import org.junit.Test;
import com.mailosaur.models.Attachment;
import com.mailosaur.models.MessageHeader;
import com.mailosaur.models.Message;
import com.mailosaur.models.MessageSummary;
import com.mailosaur.models.SearchCriteria;
import com.mailosaur.models.SearchMatchOperator;
import com.mailosaur.models.SpamAssassinRule;
import com.mailosaur.models.SpamAnalysisResult;
import com.mailosaur.models.MessageCreateOptions;
import com.mailosaur.models.MessageForwardOptions;
import com.mailosaur.models.MessageReplyOptions;

	@Test
	public void testReplyText() throws IOException, MailosaurException {
		org.junit.Assume.assumeTrue(verifiedDomain != null && !verifiedDomain.isEmpty());

		String body = "Reply message";
		String targetId = emails.get(0).id();

		MessageReplyOptions options = new MessageReplyOptions();
		options.withText(body);

		Message message = client.messages().reply(targetId, options);

		assertNotNull(message.id());
		assertTrue(message.text().body().contains(body));
	}

	@Test
	public void testReplyWithAttachment() throws IOException, MailosaurException {
		org.junit.Assume.assumeTrue(verifiedDomain != null && !verifiedDomain.isEmpty());

		String body = "New reply with attachment";
		String targetId = emails.get(0).id();

		byte[] data = Files.readAllBytes(getResourceFilePath("cat.png"));

		Attachment attachment = new Attachment();
		attachment.withFileName("cat.png");
		attachment.withContent(new String(Base64.getEncoder().encode(data)));
		attachment.withContentType("image/png");

		MessageReplyOptions options = new MessageReplyOptions();
		options.withText(body)
				.withAttachments(Arrays.asList(new Attachment[] { attachment }));

		Message message = client.messages().reply(targetId, options);

		assertEquals(1, message.attachments().size());
		Attachment file1 = message.attachments().get(0);
		assertNotNull(file1.id());
		assertEquals((Long) 82138L, file1.length());
		assertEquals("cat.png", file1.fileName());
		assertEquals("image/png", file1.contentType());
	}

	@Test
	public void testReplyHtml() throws IOException, MailosaurException {
		org.junit.Assume.assumeTrue(verifiedDomain != null && !verifiedDomain.isEmpty());

		String body = "<p>Reply <strong>HTML</strong> message.</p>";
		String targetId = emails.get(0).id();

		MessageReplyOptions options = new MessageReplyOptions();
		options.withHtml(body);

		Message message = client.messages().reply(targetId, options);

		assertNotNull(message.id());
		assertTrue(message.html().body().contains(body));
	}
    
    private void validateEmail(Message email) {
    	validateMetadata(email);
    	validateAttachments(email);
    	validateHtml(email);
    	validateText(email);
		assertNotNull(email.metadata().mailFrom());
		assertEquals(1, email.metadata().rcptTo().size());
		assertNotNull(email.metadata().rcptTo());
    }
    
    private void validateEmailSummary(MessageSummary email) {
		validateMetadata(email);
		assertNotNull(email.summary());
		assertEquals(2, (int)email.attachments());
    }
    
    private void validateHtml(Message email) {
    	// HTML.Body
    	assertTrue(email.html().body().startsWith("<div dir=\"ltr\">"));

    	// HTML.Links
    	assertEquals(3, email.html().links().size());
		assertEquals("https://mailosaur.com/", email.html().links().get(0).href());
		assertEquals("mailosaur", email.html().links().get(0).text());
		assertEquals("https://mailosaur.com/", email.html().links().get(1).href());
		assertNull(email.html().links().get(1).text());
		assertEquals("http://invalid/", email.html().links().get(2).href());
		assertEquals("invalid", email.html().links().get(2).text());

		// HTML.Codes
    	assertEquals(2, email.html().codes().size());
		assertEquals("123456", email.html().codes().get(0).value());
		assertEquals("G3H1Y2", email.html().codes().get(1).value());

		// HTML.Images
		assertTrue(email.html().images().get(1).src().startsWith("cid"));
		assertEquals("Inline image 1", email.html().images().get(1).alt());
    }
    
    private void validateText(Message email) {
    	// Text.Body
    	assertTrue(email.text().body().startsWith("this is a test"));
    	
    	// Text.Links
    	assertEquals(2, email.text().links().size());
		assertEquals("https://mailosaur.com/", email.text().links().get(0).href());
		assertEquals(email.text().links().get(0).href(), email.text().links().get(0).text());
		assertEquals("https://mailosaur.com/", email.text().links().get(1).href());
		assertEquals(email.text().links().get(1).href(), email.text().links().get(1).text());

		// Text.Codes
    	assertEquals(2, email.text().codes().size());
		assertEquals("654321", email.text().codes().get(0).value());
		assertEquals("5H0Y2", email.text().codes().get(1).value());
	}
    
    private void validateHeaders(Message email) {
    	String expectedFromHeader = String.format("%s <%s>", email.from().get(0).name(), email.from().get(0).email());
		String expectedToHeader = String.format("%s <%s>", email.to().get(0).name(), email.to().get(0).email());
		List<MessageHeader> headers = email.metadata().headers();