public function send() {
    // First verify values.
    if (!preg_match('/^.+@.+$/', $this->sender)) {
      return false;
    }
    if (!preg_match('/^.+@.+$/', $this->recipient)) {
      return false;
    }
    if (!$this->subject || strlen($this->subject) > 255) {
      return false;
    }

    // Headers that must be in the sent message.
    $required_headers = [];

    // Are we in testing mode?
    if (Mail::$config['testing_mode']) {
      // If the testing email is empty, just return true.
      if (empty(Mail::$config['testing_email'])) {
        return true;
      }
      // The testing email isn't empty, so replace stuff now.
      // Save the original to, cc, and bcc in additional headers.
      $required_headers['X-Testing-Original-To'] = $this->recipient;
      foreach ($this->headers as $name => $value) {
        switch (strtolower($name)) {
          case 'cc':
            $this->headers['X-Testing-Original-Cc'] = $value;
            $required_headers[$name] = '';
            break;
          case 'bcc':
            $this->headers['X-Testing-Original-Bcc'] = $value;
            $required_headers[$name] = '';
            break;
        }
      }
      $to = Mail::$config['testing_email'];
      $subject = '*Test* '.$this->subject;
    } else {
      $to = $this->recipient;
      $subject = $this->subject;
    }
    // Add from headers.
    $required_headers['From'] = $this->sender;
    $required_headers['Return-Path'] = $this->sender;
    $required_headers['Reply-To'] = $this->sender;
    $required_headers['X-Sender'] = $this->sender;
    $headers = $this->buildHeaders($required_headers);
    $message = $this->buildTextPart().$this->buildAttachmentPart()."--MIME_BOUNDRY--\n";

    // Now send the mail.
    return mail($to, $subject, $message, $headers, Mail::$config['additional_parameters']);
  }