5

I'm trying to send an email from a contact form that is on my page, I'm using a PHP script to send it to my email, I'm following this tutorial, I've used his example and it does work... but I can't seem to get it to work in my application, I was having some trouble at first with 404 errors but I then published my site and put it on a live server and now I'm getting success codes

enter image description here

but im not getting the emails, so I went to http://mysite/assets/email.php and Im seeing this error

enter image description here

get-in-touch.component.ts

import { Component, OnInit } from '@angular/core';
import { AppService, IMessage } from '../../services/email.service';

@Component({
  selector: 'app-get-in-touch',
  templateUrl: './get-in-touch.component.html',
  styleUrls: ['./get-in-touch.component.scss'],
  providers: [AppService]
})
export class GetInTouchComponent implements OnInit {
  message: IMessage = {};

  constructor(
    private appService: AppService
  ) { }

  ngOnInit() {
  }

  sendEmail(message: IMessage) {
    this.appService.sendEmail(message).subscribe(res => {
      console.log('AppComponent Success', res);
    }, error => {
      console.log('AppComponent Error', error);
    });
  }

}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule, Routes, ActivatedRoute, ParamMap } from '@angular/router';


import { AppComponent } from './app.component';
import { GetInTouchComponent } from './get-in-touch/get-in-touch.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { httpModule } from @angular/forms;

export const ROUTES: Routes = [
  { path: 'get-in-touch', component: GetInTouchComponent }
];

 @NgModule({
   declarations: [
    AppComponent,
    GetInTouchComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(ROUTES),
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

email.service.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Resolve } from '@angular/router';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

export interface IMessage {
  name?: string;
  email?: string;
  message?: string;
}

@Injectable()
export class AppService {
  private emailUrl = '../app/get-in-touch/email.php';

  constructor(private http: Http) {

  }

  sendEmail(message: IMessage): Observable<IMessage> | any {
    return this.http.post(this.emailUrl, message)
      .map(response => {
        console.log('Sending email was successfull', response);
        return response;
      })
      .catch(error => {
        console.log('Sending email got error', error);
        return Observable.throw(error);
      });
  }
}

email.php

<?php

header('Content-type: application/json');

$errors = '';

if(empty($errors)){
    $postdata = file_get_contents("php://input");
    $request = json_decode($postdata);

    $from_email = $request->email;
    $message = $request->message;
    $from_name = $request->name;

    $to_email = $from_email;

    $contact = "<p><strong>Name: </strong> $from_name</p><p><strong>Email:</strong> $from_email</p>";
    $content = "<p>$message</p>";

    $website = "Thirsty Studios";
    $email_subject = "Contact Form";

    $email_body = '<html><body>';
    $email_body .= '$contact $content';
    $email_body .= '</body></html>';

    $headers .= "MIME-Version: 1.0\r\n";
    $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
    $headers .= "From: $from_email\n";
    $headers .= "Reply-To: $from_email";

    mail($to_email,$email_subject,$email_body,$headers);

    $response_array['status'] = 'success';
    $response_array['from'] = $from_email;
    echo json_encode($response_array);
    echo json_encode($from_email);
    header($response_array);
    return $from_email;
} else {
    $response_array['status'] = 'error';
    echo json_encode($response_array);
    header('Location: /error.html');
}
?>

I've never done anything like this before (Angular + PHP), but I have done everything that is said in the tutorial and I can't seem to get it to work, any help would be appreciated and please let me know if you need more information

6
  • Can you check if you can actually access this URL localhost:4200/app/get-in-touch/email.php in your browser, since you are having 404 error. Commented Dec 15, 2017 at 5:51
  • Hey yes, I tried to access that URL and it didn't work so what I did was moved email.php into my assets folder and I was able to access it.. but I'm still getting the same error I'm wondering if it's not working because I am on localhost? Commented Dec 15, 2017 at 11:16
  • What is the full URL of the page where the form is displayed? Commented Dec 16, 2017 at 5:09
  • its running locally so localhost:4200/get-in-touch Commented Dec 17, 2017 at 6:14
  • Are you still getting exactly the same first error, even after you fixed the email.php URL? If not can you please update your first error image. Thanks Commented Dec 17, 2017 at 6:51

2 Answers 2

3
+50

At this point it seems as though the request does not even reach your PHP script as the request returns a 404. The first error likely occurs because the node server will not execute .php files. You will need to set up a local Apache server on a different port using something like xammp (or your preferred alternative). Or otherwise make your request to a live web server.

It seems like the second and third error messages could be coming form your .catch callback in your email service, try using the following:

.catch((error: Error) => {
  console.log('Sending email got error', error.message);
  return Observable.throw(error.message);
});

There are some alternatives to using PHP, such as formspree or even the Gmail API and I'm sure you will find others with a bit of Googling. But here is an example using fromspree.

You should also be able to simplify you PHP script slightly as follows:

<?php
$errors = '';

if( empty( $errors ) ) {

    $response_array = array();

    $from_email = $_POST['email'];
    $message    = $_POST['message'];
    $from_name  = $_POST['name'];

    $to_email = $from_email;

    $contact = "<p><strong>Name: </strong> $from_name</p><p><strong>Email:</strong> $from_email</p>";
    $content = "<p>$message</p>";

    $website = "Thirsty Studios";
    $email_subject = "Contact Form";

    $email_body = "<html><body>";
    $email_body .= "$contact $content";
    $email_body .= "</body></html>";

    $headers .= "MIME-Version: 1.0\r\n";
    $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
    $headers .= "From: $from_email\n";
    $headers .= "Reply-To: $from_email";

    mail( $to_email, $email_subject, $email_body, $headers );

    $response_array['status'] = 'success';
    $response_array['from'] = $from_email;
    echo json_encode( $response_array );

} else {

    $response_array['status'] = 'error';
    echo json_encode($response_array);
}
?>
Sign up to request clarification or add additional context in comments.

4 Comments

So I published my project and put it on a live dev server, Im getting my success messages (see updated question) but Im not actually recieving the email..
Ok, I think you can simplify your mail script slightly, see the updated answer.
@A61NN5 Did you checked your spam folder? Also do you get email when you just browse the email script? Test that first and you should understand the bug then. Also from your code this needs to be inside double quote, otherwise it will just print the variable ´$email_body .= '$contact $content';´
Hey thanks, After a lot of debugging Ive decided just to go with formspree its much simpler and it just works, thanks for the suggestion!
3

I'm not 100% convinced that I can give you an exact answer, but I think there are some overall issues/confusions/misunderstandings that you are running into, and understanding them may help get you moving in the right direction.

First of all, you should ignore the angular for now and only consider the PHP (which you have tried to do). Angular is basically a red-herring: if your can get your PHP script to send emails without using Angular, then it will be easy to get Angular to send emails using the PHP endpoint. The trick is that your script currently accepts its input via the POST body with JSON, so if you were to simply load it up in your browser, nothing will happen. Instead you can test this endpoint directly with things like curl. If you have curl installed you can do something like this from the command line:

curl -d '{"email":"[email protected]", "message": "Hi", "name": "Conor Mancone"}' 'http://example.com/email.php'

The d flag specifies the post data (and implicitly flags for a POST request). If you don't have curl installed locally you can use online curl or install postman. These are tools that you might as well start learning now.

This will let you debug your PHP endpoint much more effectively. Most importantly, you will be able to see the output directly. Next step is to copy and paste the output into something like jsonlint. It looks like your PHP endpoint is not properly returning JSON, and this will let you figure that part out. Most importantly though, you can ignore angular and figure out why you aren't sending emails. On that note, let's jump into the PHP and talk about some of the general issues in your code, which may or may not be causing your problems, but certainly aren't helping your cause:

$errors = '';

if(empty($errors)){
    // send email
} else {
    // return error
}

This first part is fairly obvious to someone who looks at your code for the first time. You make $errors empty and then all of your email-sending logic is wrapped in a if (empty($errors)) condition. Lose the $errors variable. Lose that if-else. Never leave code in your application that doesn't actually do anything. It just gives you more opportunities to introduce bugs for no reason.

Also, this is a minor point, but you aren't doing any input validation. If the JSON posted to your endpoint is missing some data your script will crash. Someone could put HTML in the message which can be obnoxious at best or dangerous at worst.

You've also got a bunch of bugs at the end of your script:

echo json_encode($response_array);
echo json_encode($from_email);
header($response_array);
return $from_email;

You are outputting $response_array as JSON to the browser, then you are running json_encode on a string ($from_email) which won't even form valid JSON, and the combination of both of them definitely won't be valid JSON. You should have only one echo json_encode, otherwise the result will not be valid JSON, and you'll get a parse error in your angular front-end.

Next up, you are passing your $response_array to the php header function. This is definitely not doing anything for you. header is expecting a string, not an array, and is used to set HTTP header key/value pairs in the HTTP response. I can't imagine you want to set any of the data in your $response_array as HTTP header response values, and even if you did want to do that, you can't do it by passing in the $response_array itself. Therefore, definitely kill this line. PHP is silently ignoring it anyway.

Similarly, there is no reason to return anything. A return from the file being executed by the HTTP request will have no impact at all. Generally, you shouldn't be returning outside of functions (and this isn't a function). While I don't believe this line is causing any errors, it also isn't doing anything. If it isn't doing anything then remove it. To be clear, I'm talking about this line: return $from_email;.

All this script should be doing is reading in the post data, sending an email, and then echoing out a single call to json_encode. Anything more than that will end up with invalid JSON which your front-end app won't be able to read. Again, use curl (or other similar tools) to call your PHP script directly and debug it more easily. This way you can see what it is outputting and verify that it is returning proper JSON.

Email

Now then, onto the main issue: lack of email sending. You've definitely got some malformed mail headers. Every mail header needs to end in \r\n. You start off good, but your last two header lines don't end properly. This might be enough to sink your email sending attempts. PHP's built in mail function doesn't do a great job of notifying you of errors, so you might actually be better off using a more robust mailer. This will give you better feedback if you make mistakes while configuring your email. A common one in PHP is this guy:

https://github.com/PHPMailer/PHPMailer

I would start by fixing your email headers and see if that does it for you. Otherwise though, you may have to try out an actual mailer. The reason is because the next most common reason why email-sending doesn't work is because of modern efforts of spam mitigation. The PHP mail function is going to send off an email directly from the server itself. Many modern email systems (especially gmail) will automatically reject such emails unless the domain name you are sending from is properly configured at the DNS level. However, you are sending from arbitrary email addresses (the contents of the $from_email variable, which comes from the user). Many email providers these days will automatically reject such emails, and PHP will have no idea that happened and won't give you any indication of it.

Instead, send from a fixed address that you control. Either pass along the $from_email in the email message, or set it as the reply-to. Your very best bet is to use an actual email address and authenticate using SMTP. Gmail actually works fine for this. You should be able to find some examples of how to use the above PHPMailer with gmail to send directly from your gmail address. This will minimize the chances of your emails being rejected as spam, and also give you additional feedback (if it is in your sent box, but didn't show up, then it was rejected as spam).

Sending emails is tricky these days. It's not as simple as calling the mail function.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.