One place for hosting & domains

      February 2021

      How To Build a Data Processing Pipeline Using Luigi in Python on Ubuntu 20.04


      The author selected the Free and Open Source Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Luigi is a Python package that manages long-running batch processing, which is the automated running of data processing jobs on batches of items. Luigi allows you to define a data processing job as a set of dependent tasks. For example, task B depends on the output of task A. And task D depends on the output of task B and task C. Luigi automatically works out what tasks it needs to run to complete a requested job.

      Overall Luigi provides a framework to develop and manage data processing pipelines. It was originally developed by Spotify, who use it to manage plumbing together collections of tasks that need to fetch and process data from a variety of sources. Within Luigi, developers at Spotify built functionality to help with their batch processing needs including handling of failures, the ability to automatically resolve dependencies between tasks, and visualization of task processing. Spotify uses Luigi to support batch processing jobs, including providing music recommendations to users, populating internal dashboards, and calculating lists of top songs.

      In this tutorial, you will build a data processing pipeline to analyze the most common words from the most popular books on Project Gutenburg. To do this, you will build a pipeline using the Luigi package. You will use Luigi tasks, targets, dependencies, and parameters to build your pipeline.

      Prerequisites

      To complete this tutorial, you will need the following:

      Step 1 — Installing Luigi

      In this step, you will create a clean sandbox environment for your Luigi installation.

      First, create a project directory. For this tutorial luigi-demo:

      Navigate into the newly created luigi-demo directory:

      Create a new virtual environment luigi-venv:

      • python3 -m venv luigi-venv

      And activate the newly created virtual environment:

      • . luigi-venv/bin/activate

      You will find (luigi-venv) appended to the front of your terminal prompt to indicate which virtual environment is active:

      Output

      (luigi-venv) username@hostname:~/luigi-demo$

      For this tutorial, you will need three libraries: luigi, beautifulsoup4, and requests. The requests library streamlines making HTTP requests; you will use it to download the Project Gutenberg book lists and the books to analyze. The beautifulsoup4 library provides functions to parse data from web pages; you will use it to parse out a list of the most popular books on the Project Gutenberg site.

      Run the following command to install these libraries using pip:

      • pip install wheel luigi beautifulsoup4 requests

      You will get a response confirming the installation of the latest versions of the libraries and all of their dependencies:

      Output

      Successfully installed beautifulsoup4-4.9.1 certifi-2020.6.20 chardet-3.0.4 docutils-0.16 idna-2.10 lockfile-0.12.2 luigi-3.0.1 python-daemon-2.2.4 python-dateutil-2.8.1 requests-2.24.0 six-1.15.0 soupsieve-2.0.1 tornado-5.1.1 urllib3-1.25.10

      You’ve installed the dependencies for your project. Now, you’ll move on to building your first Luigi task.

      Step 2 — Creating a Luigi Task

      In this step, you will create a “Hello World” Luigi task to demonstrate how they work.

      A Luigi task is where the execution of your pipeline and the definition of each task’s input and output dependencies take place. Tasks are the building blocks that you will create your pipeline from. You define them in a class, which contains:

      • A run() method that holds the logic for executing the task.
      • An output() method that returns the artifacts generated by the task. The run() method populates these artifacts.
      • An optional input() method that returns any additional tasks in your pipeline that are required to execute the current task. The run() method uses these to carry out the task.

      Create a new file hello-world.py:

      Now add the following code to your file:

      hello-world.py

      import luigi
      
      class HelloLuigi(luigi.Task):
      
          def output(self):
              return luigi.LocalTarget('hello-luigi.txt')
      
          def run(self):
              with self.output().open("w") as outfile:
                  outfile.write("Hello Luigi!")
      
      

      You define that HelloLuigi() is a Luigi task by adding the luigi.Task mixin to it.

      The output() method defines one or more Target outputs that your task produces. In the case of this example, you define a luigi.LocalTarget, which is a local file.

      Note: Luigi allows you to connect to a variety of common data sources including AWS S3 buckets, MongoDB databases, and SQL databases. You can find a complete list of supported data sources in the Luigi docs.

      The run() method contains the code you want to execute for your pipeline stage. For this example you are opening the output() target file in write mode, self.output().open("w") as outfile: and writing "Hello Luigi!" to it with outfile.write("Hello Luigi!").

      To execute the task you created, run the following command:

      • python -m luigi --module hello-world HelloLuigi --local-scheduler

      Here, you run the task using python -m instead of executing the luigi command directly; this is because Luigi can only execute code that is within the current PYTHONPATH. You can alternatively add PYTHONPATH='.' to the front of your Luigi command, like so:

      • PYTHONPATH='.' luigi --module hello-world HelloLuigi --local-scheduler

      With the --module hello-world HelloLuigi flag, you tell Luigi which Python module and Luigi task to execute.

      The --local-scheduler flag tells Luigi to not connect to a Luigi scheduler and, instead, execute this task locally. (We explain the Luigi scheduler in Step 4.) Running tasks using the local-scheduler flag is only recommended for development work.

      Luigi will output a summary of the executed tasks:

      Output

      ===== Luigi Execution Summary ===== Scheduled 1 tasks of which: * 1 ran successfully: - 1 HelloLuigi() This progress looks :) because there were no failed tasks or missing dependencies ===== Luigi Execution Summary =====

      And it will create a new file hello-luigi.txt with content:

      hello-luigi.txt

      Hello Luigi!
      

      You have created a Luigi task that generates a file and then executed it using the Luigi local-scheduler. Now, you’ll create a task that can extract a list of books from a web page.

      In this step, you will create a Luigi task and define a run() method for the task to download a list of the most popular books on Project Gutenberg. You’ll define an output() method to store links to these books in a file. You will run these using the Luigi local scheduler.

      Create a new directory data inside of your luigi-demo directory. This will be where you will store the files defined in the output() methods of your tasks. You need to create the directories before running your tasks—Python throws exceptions when you try to write a file to a directory that does not exist yet:

      • mkdir data
      • mkdir data/counts
      • mkdir data/downloads

      Create a new file word-frequency.py:

      Insert the following code, which is a Luigi task to extract a list of links to the top most-read books on Project Gutenberg:

      word-frequency.py

      import requests
      import luigi
      from bs4 import BeautifulSoup
      
      
      class GetTopBooks(luigi.Task):
          """
          Get list of the most popular books from Project Gutenberg
          """
      
          def output(self):
              return luigi.LocalTarget("data/books_list.txt")
      
          def run(self):
              resp = requests.get("http://www.gutenberg.org/browse/scores/top")
      
              soup = BeautifulSoup(resp.content, "html.parser")
      
              pageHeader = soup.find_all("h2", string="Top 100 EBooks yesterday")[0]
              listTop = pageHeader.find_next_sibling("ol")
      
              with self.output().open("w") as f:
                  for result in listTop.select("li>a"):
                      if "/ebooks/" in result["href"]:
                          f.write("http://www.gutenberg.org{link}.txt.utf-8n"
                              .format(
                                  link=result["href"]
                              )
                          )
      

      You define an output() target of file "data/books_list.txt" to store the list of books.

      In the run() method, you:

      • use the requests library to download the HTML contents of the Project Gutenberg top books page.
      • use the BeautifulSoup library to parse the contents of the page. The BeautifulSoup library allows us to scrape information out of web pages. To find out more about using the BeautifulSoup library, read the How To Scrape Web Pages with Beautiful Soup and Python 3 tutorial.
      • open the output file defined in the output() method.
      • iterate over the HTML structure to get all of the links in the Top 100 EBooks yesterday list. For this page, this is locating all links <a> that are within a list item <li>. For each of those links, if they link to a page that points at a link containing /ebooks/, you can assume it is a book and write that link to your output() file.

      Screenshot of the Project Gutenberg top books web page with the top ebooks links highlighted

      Save and exit the file once you’re done.

      Execute this new task using the following command:

      • python -m luigi --module word-frequency GetTopBooks --local-scheduler

      Luigi will output a summary of the executed tasks:

      Output

      ===== Luigi Execution Summary ===== Scheduled 1 tasks of which: * 1 ran successfully: - 1 GetTopBooks() This progress looks :) because there were no failed tasks or missing dependencies ===== Luigi Execution Summary =====

      In the data directory, Luigi will create a new file (data/books_list.txt). Run the following command to output the contents of the file:

      This file contains a list of URLs extracted from the Project Gutenberg top projects list:

      Output

      http://www.gutenberg.org/ebooks/1342.txt.utf-8 http://www.gutenberg.org/ebooks/11.txt.utf-8 http://www.gutenberg.org/ebooks/2701.txt.utf-8 http://www.gutenberg.org/ebooks/1661.txt.utf-8 http://www.gutenberg.org/ebooks/16328.txt.utf-8 http://www.gutenberg.org/ebooks/45858.txt.utf-8 http://www.gutenberg.org/ebooks/98.txt.utf-8 http://www.gutenberg.org/ebooks/84.txt.utf-8 http://www.gutenberg.org/ebooks/5200.txt.utf-8 http://www.gutenberg.org/ebooks/51461.txt.utf-8 ...

      You’ve created a task that can extract a list of books from a web page. In the next step, you’ll set up a central Luigi scheduler.

      Step 4 — Running the Luigi Scheduler

      Now, you’ll launch the Luigi scheduler to execute and visualize your tasks. You will take the task developed in Step 3 and run it using the Luigi scheduler.

      So far, you have been running Luigi using the --local-scheduler tag to run your jobs locally without allocating work to a central scheduler. This is useful for development, but for production usage it is recommended to use the Luigi scheduler. The Luigi scheduler provides:

      • A central point to execute your tasks.
      • Visualization of the execution of your tasks.

      To access the Luigi scheduler interface, you need to enable access to port 8082. To do this, run the following command:

      To run the scheduler execute the following command:

      • sudo sh -c ". luigi-venv/bin/activate ;luigid --background --port 8082"

      Note: We have re-run the virtualenv activate script as root, before launching the Luigi scheduler as a background task. This is because when running sudo the virtualenv environment variables and aliases are not carried over.

      If you do not want to run as root, you can run the Luigi scheduler as a background process for the current user. This command runs the Luigi scheduler in the background and hides messages from the scheduler background task. You can find out more about managing background processes in the terminal at How To Use Bash’s Job Control to Manage Foreground and Background Processes:

      • luigid --port 8082 > /dev/null 2> /dev/null &

      Open a browser to access the Luigi interface. This will either be at http://your_server_ip:8082, or if you have set up a domain for your server http://your_domain:8082. This will open the Luigi user interface.

      Luigi default user interface

      By default, Luigi tasks run using the Luigi scheduler. To run one of your previous tasks using the Luigi scheduler omit the --local-scheduler argument from the command. Re-run the task from Step 3 using the following command:

      • python -m luigi --module word-frequency GetTopBooks

      Refresh the Luigi scheduler user interface. You will find the GetTopBooks task added to the run list and its execution status.

      Luigi User Interface after running the GetTopBooks Task

      You will continue to refer back to this user interface to monitor the progress of your pipeline.

      Note: If you’d like to secure your Luigi scheduler through HTTPS, you can serve it through Nginx. To set up an Nginx server using HTTPS follow: How To Secure Nginx with Let’s Encrypt on Ubuntu 20.04. See Github - Luigi - Pull Request 2785 for suggestions on a suitable Nginx configuration to connect the Luigi server to Nginx.

      You’ve launched the Luigi Scheduler and used it to visualize your executed tasks. Next, you will create a task to download the list of books that the GetTopBooks() task outputs.

      Step 5 — Downloading the Books

      In this step you will create a Luigi task to download a specified book. You will define a dependency between this newly created task and the task created in Step 3.

      First open your file:

      Add an additional class following your GetTopBooks() task to the word-frequency.py file with the following code:

      word-frequency.py

      . . .
      class DownloadBooks(luigi.Task):
          """
          Download a specified list of books
          """
          FileID = luigi.IntParameter()
      
          REPLACE_LIST = """.,"';_[]:*-"""
      
          def requires(self):
              return GetTopBooks()
      
          def output(self):
              return luigi.LocalTarget("data/downloads/{}.txt".format(self.FileID))
      
          def run(self):
              with self.input().open("r") as i:
                  URL = i.read().splitlines()[self.FileID]
      
                  with self.output().open("w") as outfile:
                      book_downloads = requests.get(URL)
                      book_text = book_downloads.text
      
                      for char in self.REPLACE_LIST:
                          book_text = book_text.replace(char, " ")
      
                      book_text = book_text.lower()
                      outfile.write(book_text)
      

      In this task you introduce a Parameter; in this case, an integer parameter. Luigi parameters are inputs to your tasks that affect the execution of the pipeline. Here you introduce a parameter FileID to specify a line in your list of URLs to fetch.

      You have added an additional method to your Luigi task, def requires(); in this method you define the Luigi task that you need the output of before you can execute this task. You require the output of the GetTopBooks() task you defined in Step 3.

      In the output() method, you define your target. You use the FileID parameter to create a name for the file created by this step. In this case, you format data/downloads/{FileID}.txt.

      In the run() method, you:

      • open the list of books generated in the GetTopBooks() task.
      • get the URL from the line specified by parameter FileID.
      • use the requests library to download the contents of the book from the URL.
      • filter out any special characters inside the book like :,.?, so they don’t get included in your word analysis.
      • convert the text to lowercase so you can compare words with different cases.
      • write the filtered output to the file specified in the output() method.

      Save and exit your file.

      Run the new DownloadBooks() task using this command:

      • python -m luigi --module word-frequency DownloadBooks --FileID 2

      In this command, you set the FileID parameter using the --FileID argument.

      Note: Be careful when defining a parameter with an _ in the name. To reference them in Luigi you need to substitute the _ for a -. For example, a File_ID parameter would be referenced as --File-ID when calling a task from the terminal.

      You will receive the following output:

      Output

      ===== Luigi Execution Summary ===== Scheduled 2 tasks of which: * 1 complete ones were encountered: - 1 GetTopBooks() * 1 ran successfully: - 1 DownloadBooks(FileID=2) This progress looks :) because there were no failed tasks or missing dependencies ===== Luigi Execution Summary =====

      Note from the output that Luigi has detected that you have already generated the output of GetTopBooks() and skipped running that task. This functionality allows you to minimize the number of tasks you have to execute as you can re-use successful output from previous runs.

      You have created a task that uses the output of another task and downloads a set of books to analyze. In the next step, you will create a task to count the most common words in a downloaded book.

      Step 6 — Counting Words and Summarizing Results

      In this step, you will create a Luigi task to count the frequency of words in each of the books downloaded in Step 5. This will be your first task that executes in parallel.

      First open your file again:

      Add the following imports to the top of word-frequency.py:

      word-frequency.py

      from collections import Counter
      import pickle
      

      Add the following task to word-frequency.py, after your DownloadBooks() task. This task takes the output of the previous DownloadBooks() task for a specified book, and returns the most common words in that book:

      word-frequency.py

      class CountWords(luigi.Task):
          """
          Count the frequency of the most common words from a file
          """
      
          FileID = luigi.IntParameter()
      
          def requires(self):
              return DownloadBooks(FileID=self.FileID)
      
          def output(self):
              return luigi.LocalTarget(
                  "data/counts/count_{}.pickle".format(self.FileID),
                  format=luigi.format.Nop
              )
      
          def run(self):
              with self.input().open("r") as i:
                  word_count = Counter(i.read().split())
      
                  with self.output().open("w") as outfile:
                      pickle.dump(word_count, outfile)
      

      When you define requires() you pass the FileID parameter to the next task. When you specify that a task depends on another task, you specify the parameters you need the dependent task to be executed with.

      In the run() method you:

      • open the file generated by the DownloadBooks() task.
      • use the built-in Counter object in the collections library. This provides an easy way to analyze the most common words in a book.
      • use the pickle library to store the output of the Python Counter object, so you can re-use that object in a later task. pickle is a library that you use to convert Python objects into a byte stream, which you can store and restore into a later Python session. You have to set the format property of the luigi.LocalTarget to allow it to write the binary output the pickle library generates.

      Save and exit your file.

      Run the new CountWords() task using this command:

      • python -m luigi --module word-frequency CountWords --FileID 2

      Open the CountWords task graph view in the Luigi scheduler user interface.

      Showing how to view a graph from the Luigi user interface

      Deselect the Hide Done option, and deselect Upstream Dependencies. You will find the flow of execution from the tasks you have created.

      Visualizing the execution of the CountWords task

      You have created a task to count the most common words in a downloaded book and visualized the dependencies between those tasks. Next, you will define parameters that you can use to customize the execution of your tasks.

      Step 7 — Defining Configuration Parameters

      In this step, you will add configuration parameters to the pipeline. These will allow you to customize how many books to analyze and the number of words to include in the results.

      When you want to set parameters that are shared among tasks, you can create a Config() class. Other pipeline stages can reference the parameters defined in the Config() class; these are set by the pipeline when executing a job.

      Add the following Config() class to the end of word-frequency.py. This will define two new parameters in your pipeline for the number of books to analyze and the number of most frequent words to include in the summary:

      word-frequency.py

      class GlobalParams(luigi.Config):
          NumberBooks = luigi.IntParameter(default=10)
          NumberTopWords = luigi.IntParameter(default=500)
      

      Add the following class to word-frequency.py. This class aggregates the results from all of the CountWords() task to create a summary of the most frequent words:

      word-frequency.py

      class TopWords(luigi.Task):
          """
          Aggregate the count results from the different files
          """
      
          def requires(self):
              requiredInputs = []
              for i in range(GlobalParams().NumberBooks):
                  requiredInputs.append(CountWords(FileID=i))
              return requiredInputs
      
          def output(self):
              return luigi.LocalTarget("data/summary.txt")
      
          def run(self):
              total_count = Counter()
              for input in self.input():
                  with input.open("rb") as infile:
                      nextCounter = pickle.load(infile)
                      total_count += nextCounter
      
              with self.output().open("w") as f:
                  for item in total_count.most_common(GlobalParams().NumberTopWords):
                      f.write("{0: <15}{1}n".format(*item))
      
      

      In the requires() method, you can provide a list where you want a task to use the output of multiple dependent tasks. You use the GlobalParams().NumberBooks parameter to set the number of books you need word counts from.

      In the output() method, you define a data/summary.txt output file that will be the final output of your pipeline.

      In the run() method you:

      • create a Counter() object to store the total count.
      • open the file and “unpickle” it (convert it from a file back to a Python object), for each count carried out in the CountWords() method
      • append the loaded count and add it to the total count.
      • write the most common words to target output file.

      Run the pipeline with the following command:

      • python -m luigi --module word-frequency TopWords --GlobalParams-NumberBooks 15 --GlobalParams-NumberTopWords 750

      Luigi will execute the remaining tasks needed to generate the summary of the top words:

      Output

      ===== Luigi Execution Summary ===== Scheduled 31 tasks of which: * 2 complete ones were encountered: - 1 CountWords(FileID=2) - 1 GetTopBooks() * 29 ran successfully: - 14 CountWords(FileID=0,1,10,11,12,13,14,3,4,5,6,7,8,9) - 14 DownloadBooks(FileID=0,1,10,11,12,13,14,3,4,5,6,7,8,9) - 1 TopWords() This progress looks :) because there were no failed tasks or missing dependencies ===== Luigi Execution Summary =====

      You can visualize the execution of the pipeline from the Luigi scheduler. Select the GetTopBooks task in the task list and press the View Graph button.

      Showing how to view a graph from the Luigi user interface

      Deselect the Hide Done and Upstream Dependencies options.

      Visualizing the execution of the TopWords Task

      It will show the flow of processing that is happening in Luigi.

      Open the data/summary.txt file:

      You will find the calculated most common words:

      Output

      the 64593 and 41650 of 31896 to 31368 a 25265 i 23449 in 19496 it 16282 that 15907 he 14974 ...

      In this step, you have defined and used parameters to customize the execution of your tasks. You have generated a summary of the most common words for a set of books.

      Find all the code for this tutorial in this repository.

      Conclusion

      This tutorial has introduced you to using the Luigi data processing pipeline and its major features including tasks, parameters, configuration parameters, and the Luigi scheduler.

      Luigi supports connecting to a large number of common data sources out the box. You can also scale it to run large, complex data pipelines. This provides a powerful framework to start solving your data processing challenges.

      For more tutorials, check out our Data Analysis topic page and Python topic page.



      Source link

      How to Fix the WordPress Not Sending Email Issue


      Dealing with email issues can be a frustrating experience. Whether you’re not receiving important WordPress notifications or your contact form seems to be acting up, these problems can disrupt your day-to-day business.

      Fortunately, there are multiple troubleshooting methods and tools you can use to fix your email issues. Most aren’t overly complicated, and you’ll still be able to decide what email addresses you’ll use to send and receive messages from WordPress.

      In this article, we’ll explain some likely reasons WordPress isn’t sending emails. Then we’ll show you how to fix this issue and configure your contact forms so that they properly deliver emails as well. Let’s go!

      Need to Fix WordPress Issues? We’ve Got You

      Avoid troubleshooting when you partner with DreamHost. Our friendly WordPress experts are available 24/7 to help solve website problems — big or small.

      Why You’re Not Receiving Emails From WordPress

      By default, WordPress uses the PHP mail() function to send emails. Unfortunately, many hosting servers are not configured to use this function, making it impossible to process those emails.

      Another reason emails from your site may not get delivered is unintended side effects from efforts to reduce spam. Most email providers attempt to verify that an email is coming from the address it claims.

      However, the address used to send email from your website likely uses spoofing. Without spoofing, an email sent from your website might look like “[email protected]”. Spoofing enables you to change that address to a more reasonable one, such as ‘“[email protected]”.

      Unfortunately, spoofing can also serve nefarious purposes, and email providers can’t tell the difference. Therefore, it can sometimes cause your emails to end up in recipients’ spam folders.

      How to Stop Email From Going to Spam

      In addition to spoofing, there are a lot of other reasons why emails might go to spam. Some of the most common possibilities are:

      • Your IP address is flagged as having been used for spam
      • You’re using trigger words in your email newsletters
      • You’re employing poor emailing practices

      One way to keep your emails out of the spam bin is to use Simple Mail Transfer Protocol (SMTP) rather than PHP mail(). This protocol is the industry standard and uses proper authentication.

      Put simply, emails sent via SMTP have a higher chance of being delivered than those sent using other protocols. You can use a few different methods to set up your WordPress site to send emails via SMTP.

      How to Set Up WordPress to Send Emails Via SMTP (2 Ways)

      Now that we’ve touched on a few reasons WordPress emails aren’t making it to their intended recipients, let’s look at two ways to fix the problem.

      1. Send Email Using Your Hosting Account Address

      Using your hosting account email is the simplest way to get your WordPress messages moving as expected. We’ll show you how to set this up, using our own DreamHost web hosting as an example.

      Begin by downloading and installing the WP Mail SMTP plugin. From your WordPress dashboard, navigate to WP Mail SMTP > Settings.

      The settings screen of WP Mail SMTP.

      There are several fields you’ll need to fill in on this screen. From Email is the address from which you want your emails sent. You’ll also need to check the Force From Email box. The From Name field is the name you’d like the email to come from. You can check the Force From Name box if you’d like.

      Finally, select Other SMTP as your mailer. Doing this will cause a Return Path section to appear. Be sure to click on the box in that section as well.

      Now you can populate the other SMTP options. We’ll use DreamHost to demonstrate again, but the information should be similar if you use another web host.

      WP Mail SMTP settings for other SMTP mailers.

      First, make sure to toggle on Authentication. For the SMTP Host, use “smtp.dreamhost.com”. When you select TLS encryption, the plugin should auto-populate the SMTP port as “587”.

      Next, you can enter your DreamHost email address and password. Finally, click on the Save Settings button, and you should be ready to go. You can try sending a test email to be sure that everything is working properly.

      2. Send Email Using Your Gmail Account

      If you prefer, you can use your Gmail address to send mail. Note that while this method also uses the WP Mail SMTP plugin, it’s significantly more complicated. Also, you’ll have to perform these steps again if you ever change your Gmail address.

      First, set up a Gmail account to use, if you don’t already have one. Next, download and install the WP Mail SMTP plugin, and navigate to WP Mail SMTP > Settings. You can fill out the fields as described above.

      However, when it’s time to select your mailer, choose Gmail.

      WP Mail SMTP settings for the Gmail mailer.

      Please keep this tab handy, as we’ll need to return to it later. For now, you can create a set of secure credentials that will provide your WordPress installation with the required authorization to use Gmail’s servers.

      To configure these credentials, head to the Google Developers Console and log in. Create a new project by clicking on Select a project at the top of the screen, followed by New Project in the pop-up that appears.

      Creating a new project in Google Developers Console.

      Give your project whatever name you’d like, and then click on the Create button. Once you do, you’ll be brought to the API Library. Find and click on the Gmail API in the G Suite section.

      Google’s API Library.

      Select the Enable button. On the next screen, click on Create credentials to open the credentials wizard.

      Opening the Gmail API credentials wizard.

      Next, select the Client ID link. You’ll see a pop-up asking you to set up a consent screen. Click on the Set Up Consent Screen button to proceed.

      Here, you’ll select whether the application type is internal or external. If you’re not using a G Suite account, you’ll only be able to choose “external.”

      Setting up an OAuth consent screen.

      You can provide an application name and a contact email address. After you do, scroll down to the Authorized domains section, click on Add domain, and enter your website’s URL.

      Adding an authorized domain.

      Finally, enter your email address again under Developer contact information. Click on the Save and Continue button. You can also hit Save and Continue to advance through the next two screens. Since you’re the only one who will ever see this page, you don’t need to worry about populating that information.

      When you reach the end of this series of prompts, click on the Back to Dashboard button. Select the Credentials tab on the left, followed by Create Credentials > OAuth Client ID from the drop-down menu.

      Creating an OAuth client ID.

      On the next page, select Web Application from the Application type drop-down menu. You’ll need to return to the WP Mail SMTP settings screen. Copy the Authorized Redirect URL, and paste it into the Authorized Redirect URL field on the Client ID for Web Application page.

      Adding an authorized redirect URL.

      When you’re done, click on the Create button. You’ll see a pop-up containing the Client ID and Client Secret. Paste these OAuth credentials into the appropriate fields in the WP Mail SMTP options.

      Adding the client ID and client secret to WP Mail SMTP.

      Once you click on the Save Settings button, the page will refresh. Scroll back down to the bottom and click on Allow plugin to send emails using your Gmail account.

      The grant permission button.

      Enter your Gmail credentials to finalize the connection. Your SMTP status should now be connected, and you can send a test email to make sure everything is working correctly.

      How to Configure Your Contact Forms to Send Email Successfully

      If your server is now sending emails correctly, but you are still having problems with your contact forms, the issue could be with a setting in the WordPress form plugin you use. Below, we’ll show you how to troubleshoot some of the most popular tools.

      Contact Form 7

      If Contact Form 7 isn’t working for you, you likely need to change the address from which emails are sent. Starting from the admin dashboard, navigate to Contact > Contact Forms. Next, click on the contact form you’d like to edit and select the Mail tab.

      The Contact Form 7 settings page.

      Ensure that the From field is using your website’s admin email address. Also, verify that the emails in the To and From fields are different. Once you’ve made the necessary changes, click on the Save button.

      WPForms Lite

      You can change the settings in WPForms Lite by navigating to WP Forms > All Forms. To open the editor, click on Edit under the form you want to change. Next, select Settings in the left-hand menu, followed by Notifications.

      The WPForms settings page.

      Here, you’ll be able to update the Send To Email Address and From Email fields. Click on the Save button when you’ve made your desired changes.

      Jetpack

      You’re less likely to run into problems using Jetpack’s contact form, as this plugin doesn’t give you as many configuration options. If there is an issue, it probably stems from having the same email address set as both To and From.

      You can correct this by making one simple change. After you’ve added the form using the block, click on the pencil icon to edit the form options.

      Settings for the Jetpack Form Block.

      You can change the email address your form responses send to on this screen. Note that you won’t be able to change the address that forms are sent from, as Jetpack uses your website’s admin email for this.

      Take Your WordPress Site to the Next Level

      Whether you need help with plugin settings, transactional emails, or smtp authentication, we can help! Subscribe to our monthly digest so you never miss an article.

      Ready to Fix the WordPress Not Sending Email Issue?

      There are few things as irritating as having to dig through your spam folder to look for a missing email. However, once you’ve fixed this common WordPress issue, your website’s emails should safely find their way to their intended destinations.

      In this piece, we showed you how to leverage the WP Mail SMTP plugin, and use either your hosting or Gmail account to send emails. Once you’ve handled that task, you can move on to configuring the options in your contact form plugin, to ensure that those emails properly send as well.

      If you’d like to make your experience with WordPress emails easier, you might want to consider checking out DreamPress, our managed hosting plan. You’ll have access to our premium support 24/7 to help you with any problems you may run into on your site!



      Source link

      What is Laravel?


      Laravel is a free and open-source PHP framework that provides a set of tools and resources to build modern PHP applications. With a complete ecosystem leveraging its built-in features, and a variety of compatible packages and extensions, Laravel has seen its popularity grow rapidly in the past few years, with many developers adopting it as their framework of choice for a streamlined development process.

      Laravel provides powerful database tools including an ORM (Object Relational Mapper) called Eloquent, and built-in mechanisms for creating database migrations and seeders. With the command-line tool Artisan, developers can bootstrap new models, controllers, and other application components, which speeds up the overall application development.

      For a project-based introduction to Laravel, you can refer to our series on How to Build a Links Landing Page in PHP with Laravel and Docker Compose, which goes over how to bootstrap a new Laravel application in a containerized development environment, how to interact with the database, and how to customize the page template view to show a list of curated links.

      For other Laravel tutorials, please refer to our comprehensive list of educational materials on that framework.



      Source link