How to store state in module?

So, I’m building an SMTP client that I’d like to be able to be called from different processes and have different state for each process. The SMTP client needs to track for example if the HELO command has been used or not. How do I handle state?

My current code is this:

defmodule Client do
  @moduledoc """
  Documentation for `Smtpclient`.
  """

  use Agent

  def start_link(_opts) do
    Agent.start_link(fn -> %{} end, name: __MODULE__)
  end


  def connect(pid, tld) do
      set_value(pid, "tld", tld)
      {:ok, records} = DNS.resolve(tld, :mx)
      Enum.sort_by(records, fn(r) -> elem(r, 0) end)
      sock = do_connect(records, 0)
      set_socket(pid, sock)
      set_value(pid, "hostname", tld)
      {:ok, sock}
  end

  @spec helo(any) :: any
  def helo(pid) do
      already_helloed = get_value(pid, "already_helloed")
      if already_helloed do # if already helloed return early
        {:error, "already helloed"}
      end
      sock = get_socket(pid)
      tld = get_value(pid, "tld")
      sock |> Socket.Stream.send!("HELO #{tld}")
      set_value(pid, "already_helloed", true)
      sock |> Socket.Stream.recv!
  end

  def noop(pid) do
    try do
      sock = get_socket(pid)
      sock |> Socket.Stream.send!("NOOP")
      sock |> Socket.Stream.recv!
    rescue
      Socker.Error -> {:error, :no_connection}
    end
  end

  def quit(sock) do
      try do
        sock |> Socket.Stream.send!("QUIT")
        sock |> Socket.Stream.recv!
        sock |> Socket.close!()
      rescue
        Socket.Error -> {:error, "something is wrong"}
      end
  end

  def rctp_to(pid, email) do
    try do
      sock = get_socket(pid)
      sock |> Socket.Stream.send!("RCPT_TO #{email}")
      sock |> Socket.Stream.recv!
    rescue
      Socker.Error -> {:error, "something is wrong"}
    end
  end

  defp set_socket(pid, sock) do
    Agent.update(pid, &Map.put(&1, "socket", sock))
  end

  defp get_socket(pid) do
    Agent.get(pid, &Map.get(&1, "socket"))
  end

  defp set_value(pid, key, value) do
    Agent.update(pid, &Map.put(&1, key, value))
  end

  defp get_value(pid, key) do
    Agent.get(pid, &Map.get(&1, key))
  end

  defp do_connect(hostnames, i) do
    try do
      host = elem(Enum.at(hostnames, i), 1)
      Socket.TCP.connect!(to_string(host), 25, packet: :line)
    rescue
        Socket.Error ->
          if Enum.at(hostnames, i) == nil do
            {:error, "all mx servers down"}
          end
          do_connect(hostnames, i + 1)
    end
  end
end